From b703c7e26b4f92789dfdfcee4a72994862b0e4f3 Mon Sep 17 00:00:00 2001
From: "francois.grand" <francois.grand@irstea.fr>
Date: Tue, 16 Jan 2018 17:36:35 +0100
Subject: [PATCH 01/10] =?UTF-8?q?ticket=20#47=20:=20ajout=20d'un=20mode=20?=
 =?UTF-8?q?"liste=20de=20valeur"=20pour=20les=20param=C3=A8tres=20=C3=A0?=
 =?UTF-8?q?=20varier=20-=20composants=20NgParamMinComponent,=20NgParamMaxC?=
 =?UTF-8?q?omponent,=20NgParamStepComponent=20chacun=20dans=20leur=20fichi?=
 =?UTF-8?q?er=20-=20cr=C3=A9ation=20d'un=20composant=20ValueListComponent?=
 =?UTF-8?q?=20pour=20g=C3=A9rer=20le=20"mode=20min/max/pas"=20et=20"liste?=
 =?UTF-8?q?=20de=20valeurs"=20-=20NgParameter=20:=20ajout=20d'un=20enum=20?=
 =?UTF-8?q?pour=20indiquer=20le=20mode=20de=20g=C3=A9n=C3=A9ration=20des?=
 =?UTF-8?q?=20valeurs=20=C3=A0=20varier?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/app/app.module.ts                         |   7 +-
 .../param-field-line.component.html           |  12 +-
 .../param-field-line.component.ts             | 365 +-----------------
 src/app/formulaire/formulaire-definition.ts   |  45 ++-
 src/app/formulaire/ngparam.ts                 |  17 +
 src/index.html                                |   4 +-
 6 files changed, 60 insertions(+), 390 deletions(-)

diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index c7a5daded..cdec1aedb 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -16,7 +16,11 @@ import { ApplicationSetupService } from "./services/app-setup/app-setup.service"
 import { AppComponent } from './app.component';
 import { NgParamInputComponent } from './components/ngparam-input/ngparam-input.component';
 import { FieldSetComponent } from './components/field-set/field-set.component';
-import { ParamFieldLineComponent, NgParamMinComponent, NgParamMaxComponent, NgParamStepComponent } from './components/param-field-line/param-field-line.component';
+import { ParamFieldLineComponent } from './components/param-field-line/param-field-line.component';
+import { NgParamMinComponent } from './components/param-values/ngparam-min.component';
+import { NgParamMaxComponent } from './components/param-values/ngparam-max.component';
+import { NgParamStepComponent } from './components/param-values/ngparam-step.component';
+import { ParamValuesComponent, ValueListComponent } from './components/param-values/param-values.component';
 import { SelectFieldLineComponent } from './components/select-field-line/select-field-line.component';
 import { CheckFieldLineComponent } from './components/check-field-line/check-field-line.component';
 // import { AlertDialog } from './components/alert-dialog/alert-dialog.component';
@@ -62,6 +66,7 @@ const appRoutes: Routes = [
     NgParamInputComponent,
     FieldSetComponent,
     ParamFieldLineComponent, NgParamMinComponent, NgParamMaxComponent, NgParamStepComponent,
+    ParamValuesComponent, ValueListComponent, 
     SelectFieldLineComponent, CheckFieldLineComponent,
     LogComponent,
     CalculatorListComponent,
diff --git a/src/app/components/param-field-line/param-field-line.component.html b/src/app/components/param-field-line/param-field-line.component.html
index 7b34c4ecd..753b689b3 100644
--- a/src/app/components/param-field-line/param-field-line.component.html
+++ b/src/app/components/param-field-line/param-field-line.component.html
@@ -29,14 +29,4 @@
     </div>
 </div>
 
-<div *ngIf="isRadioVarChecked" class="row">
-    <div class="col-12 col-sm-4">
-        <ngparam-min [title]="uitextValeurMini" (onChange)="onMinChanged($event)"></ngparam-min>
-    </div>
-    <div class="col-12 col-sm-4">
-        <ngparam-max [title]="uitextValeurMaxi" (onChange)="onMaxChanged($event)"></ngparam-max>
-    </div>
-    <div class="col-12 col-sm-4">
-        <ngparam-step [title]="uitextPasVariation" (onChange)="onStepChanged($event)"></ngparam-step>
-    </div>
-</div>
\ No newline at end of file
+<param-values *ngIf="isRadioVarChecked" [param]="_param"></param-values>
\ No newline at end of file
diff --git a/src/app/components/param-field-line/param-field-line.component.ts b/src/app/components/param-field-line/param-field-line.component.ts
index eaea2232e..6e7a402ee 100644
--- a/src/app/components/param-field-line/param-field-line.component.ts
+++ b/src/app/components/param-field-line/param-field-line.component.ts
@@ -1,229 +1,9 @@
-import { Component, ViewChild, Input, Output, DoCheck, EventEmitter } from "@angular/core";
-
-import { NumericalString, ParamDomainValue, Pair } from "jalhyd";
+import { Component, ViewChild, Input, Output, EventEmitter } from "@angular/core";
 
 import { InternationalisationService } from "../../services/internationalisation/internationalisation.service";
 import { NgParameter, ParamRadioConfig } from "../../formulaire/ngparam";
 import { GenericInputComponent } from "../generic-input/generic-input.component";
 
-@Component({
-    selector: "ngparam-min",
-    templateUrl: "../generic-input/generic-input.component.html"
-})
-export class NgParamMinComponent extends GenericInputComponent {
-    /**
-     * valeur actuelle du minimum
-     */0.49999999995
-    private _currentValue: number;
-
-    /**
-     * reférence (valeur mini pour le minimum)
-     */
-    private _refValue: Pair;
-
-    @Output()
-    private onChange = new EventEmitter<string>();
-
-    public isInit: boolean;
-
-    constructor(private intlService: InternationalisationService) {
-        super();
-    }
-
-    public set refValue(v: Pair) {
-        this._refValue = v;
-    }
-
-    protected getModelValue(): any {
-        return this._currentValue;
-    }
-
-    protected setModelValue(v: any) {
-        this._currentValue = v;
-        this.onChange.emit("value");
-    }
-
-    protected validateModelValue(v: any): { isValid: boolean, message: string } {
-        let msg = undefined;
-        let valid = false;
-
-        if (!this._refValue.intervalHasValue(v))
-            msg = "La valeur n'est pas dans " + this._refValue.toString();
-        else
-            valid = true;
-
-        return { isValid: valid, message: msg };
-    }
-
-    protected modelToUI(v: any): string {
-        if (typeof (v) == "number")
-            return String(v);
-        return undefined;
-    }
-
-    protected validateUIValue(ui: string): { isValid: boolean, message: string } {
-        let valid: boolean = false;
-        let msg: string = undefined;
-
-        let v: NumericalString = new NumericalString(ui);
-        if (!v.isNumerical)
-            msg = "Veuillez entrer une valeur numérique";
-        else
-            valid = true;
-
-        return { isValid: valid, message: msg };
-    }
-
-    protected uiToModel(ui: string): any {
-        return +ui;
-    }
-}
-
-@Component({
-    selector: "ngparam-max",
-    templateUrl: "../generic-input/generic-input.component.html"
-})
-export class NgParamMaxComponent extends GenericInputComponent {
-    /**
-       * valeur actuelle du maximum
-       */
-    private _currentValue: number;
-
-    /**
-     * reférence (valeur maxi pour le maximum)
-     */
-    private _refValue: Pair;
-
-    @Output()
-    private onChange = new EventEmitter<string>();
-
-    constructor(private intlService: InternationalisationService) {
-        super();
-    }
-
-    public set refValue(v: Pair) {
-        this._refValue = v;
-    }
-
-    protected getModelValue(): any {
-        return this._currentValue;
-    }
-
-    protected setModelValue(v: any) {
-        this._currentValue = v;
-        this.onChange.emit("value");
-    }
-
-    protected validateModelValue(v: any): { isValid: boolean, message: string } {
-        let msg = undefined;
-        let valid = false;
-
-        if (!this._refValue.intervalHasValue(v))
-            msg = "La valeur n'est pas dans " + this._refValue.toString();
-        else
-            valid = true;
-
-        return { isValid: valid, message: msg };
-    }
-
-    protected modelToUI(v: any): string {
-        if (typeof (v) == "number")
-            return String(v);
-        return undefined;
-    }
-
-    protected validateUIValue(ui: string): { isValid: boolean, message: string } {
-        let valid: boolean = false;
-        let msg: string = undefined;
-
-        let v: NumericalString = new NumericalString(ui);
-        if (!v.isNumerical)
-            msg = "Veuillez entrer une valeur numérique";
-        else
-            valid = true;
-
-        return { isValid: valid, message: msg };
-    }
-
-    protected uiToModel(ui: string) {
-        return +ui;
-    }
-}
-
-@Component({
-    selector: "ngparam-step",
-    templateUrl: "../generic-input/generic-input.component.html"
-})
-export class NgParamStepComponent extends GenericInputComponent {
-    /**
-     * valeur actuelle du pas
-     */
-    private _currentValue: number;
-
-    /**
-     * reférence (valeur maxi pour le pas)
-     */
-    private _refValue: Pair;
-
-    @Output()
-    private onChange = new EventEmitter<string>();
-
-    constructor(private intlService: InternationalisationService) {
-        super();
-    }
-
-    public set refValue(v: Pair) {
-        this._refValue = v;
-    }
-
-    protected getModelValue(): any {
-        return this._currentValue;
-    }
-
-    protected setModelValue(v: any) {
-        this._currentValue = v;
-        this.onChange.emit("value");
-    }
-
-    protected validateModelValue(v: any): { isValid: boolean, message: string } {
-        let msg = undefined;
-        let valid = false;
-
-        if (!this._refValue.intervalHasValue(v))
-            msg = "La valeur n'est pas dans " + this._refValue.toString();
-        else {
-            valid = v > 0;
-            if (!valid)
-                msg = "La valeur ne peut pas être <= 0";
-        }
-
-        return { isValid: valid, message: msg };
-    }
-
-    protected modelToUI(v: any): string {
-        if (typeof (v) == "number")
-            return String(v);
-        return "<invalid>";
-    }
-
-    protected validateUIValue(ui: string): { isValid: boolean, message: string } {
-        let valid: boolean = false;
-        let msg: string = undefined;
-
-        let v: NumericalString = new NumericalString(ui);
-        if (!v.isNumerical)
-            msg = "Veuillez entrer une valeur numérique";
-        else
-            valid = true;
-
-        return { isValid: valid, message: msg };
-    }
-
-    protected uiToModel(ui: string) {
-        return +ui;
-    }
-}
-
 @Component({
     selector: "param-field-line",
     templateUrl: "./param-field-line.component.html",
@@ -244,142 +24,13 @@ export class NgParamStepComponent extends GenericInputComponent {
         }`
     ]
 })
-export class ParamFieldLineComponent implements DoCheck {
+export class ParamFieldLineComponent {
     @Input("param")
     private _param: NgParameter;
 
-    /**
-     * composant de saisie du minimum
-     */
-    @ViewChild(NgParamMinComponent)
-    private _minComponent: NgParamMinComponent;
-
-    /**
-     * composant de saisie du maximum
-     */
-    @ViewChild(NgParamMaxComponent)
-    private _maxComponent: NgParamMaxComponent;
-
-    /**
-     * composant de saisie du pas de variation
-     */
-    @ViewChild(NgParamStepComponent)
-    private _stepComponent: NgParamStepComponent;
-
     constructor(private intlService: InternationalisationService) {
     }
 
-    private getDefaultMin(): number {
-        switch (this._param.domain.domain) {
-            case ParamDomainValue.ANY:
-            case ParamDomainValue.NOT_NULL:
-                return -10;
-
-            default:
-                return this._param.domain.minValue;
-        }
-    }
-
-    private getDefaultMax(): number {
-        switch (this._param.domain.domain) {
-            case ParamDomainValue.INTERVAL:
-                return this._param.domain.maxValue;
-
-            default:
-                return 10;
-        }
-    }
-
-    private initMinMaxStep() {
-        // valeur pour min (celle déjà définie ou celle déduite du domaine de définition)
-        let min: number = this._param.minValue;
-        let ok = min != undefined
-        if (ok) {
-            try {
-                // on la vérifie
-                this._param.checkValue(min);
-                ok = true;
-            }
-            catch (e) {
-                ok = false;
-            }
-        }
-        if (!ok)
-            min = this.getDefaultMin();
-
-        // valeur pour max (celle déjà définie ou celle déduite du domaine de définition)
-        let max: number = this._param.maxValue;
-        ok = max != undefined
-        if (ok) {
-            try {
-                // on la vérifie
-                this._param.checkValue(max);
-                ok = true;
-            }
-            catch (e) {
-                ok = false;
-            }
-        }
-        if (!ok)
-            min = this.getDefaultMax();
-
-        this._minComponent.refValue = new Pair(this._param.domain.minValue, max);
-        this._minComponent.model = min;
-
-        this._maxComponent.refValue = new Pair(min, this._param.domain.maxValue);
-        this._maxComponent.model = max;
-
-        this.updateStepComponentRef();
-
-        let step = this._param.stepValue;
-        if (step == undefined)
-            step = (max - min) / 20;
-        if (min == -Infinity || max == Infinity)
-            step = 10;
-        this._stepComponent.model = step;
-    }
-
-    private onMinChanged(val: string) {
-        this.updateStepComponentRef();
-
-        this._maxComponent.refValue = new Pair(this._minComponent.model, this._param.domain.maxValue);
-        this._maxComponent.validateModel();
-
-        if (this._minComponent.validateModel())
-            this._param.minValue = this._minComponent.model;
-    }
-
-    private onMaxChanged(val: string) {
-        this.updateStepComponentRef();
-
-        this._minComponent.refValue = new Pair(this._param.domain.minValue, this._maxComponent.model);
-        this._minComponent.validateModel();
-
-        if (this._maxComponent.validateModel())
-            this._param.maxValue = this._maxComponent.model;
-    }
-
-    private onStepChanged(val: string) {
-        if (this._stepComponent.validateModel())
-            this._param.stepValue = this._stepComponent.model;
-    }
-
-    public ngDoCheck() {
-        // initialisation des champs min/max/step à l'apparition de ces contrôles
-        if (this._minComponent != undefined && !this._minComponent.isInit) {
-            this._minComponent.isInit = true;
-            this.initMinMaxStep();
-        }
-    }
-
-    /**
-     * met à jour la valeur de référence du composant gérant le pas de variation
-     */
-    private updateStepComponentRef() {
-        this._stepComponent.refValue = new Pair(1e-9, this._maxComponent.model - this._minComponent.model);
-        this._stepComponent.validateModel();
-    }
-
     private get title(): string {
         let t = "";
         if (this._param.label != undefined)
@@ -397,18 +48,6 @@ export class ParamFieldLineComponent implements DoCheck {
         return this.intlService.localizeText("INFO_PARAMFIELD_PARAMVARIER");
     }
 
-    private get uitextValeurMini() {
-        return this.intlService.localizeText("INFO_PARAMFIELD_VALEURMINI");
-    }
-
-    private get uitextValeurMaxi() {
-        return this.intlService.localizeText("INFO_PARAMFIELD_VALEURMAXI");
-    }
-
-    private get uitextPasVariation() {
-        return this.intlService.localizeText("INFO_PARAMFIELD_PASVARIATION");
-    }
-
     private get uitextParamCalculer() {
         return this.intlService.localizeText("INFO_PARAMFIELD_PARAMCALCULER");
     }
diff --git a/src/app/formulaire/formulaire-definition.ts b/src/app/formulaire/formulaire-definition.ts
index 00fe09485..fc847e626 100644
--- a/src/app/formulaire/formulaire-definition.ts
+++ b/src/app/formulaire/formulaire-definition.ts
@@ -7,7 +7,7 @@ import { ParamService } from "../services/param/param.service";
 import { InternationalisationService } from "../services/internationalisation/internationalisation.service";
 import { ApplicationSetupService } from "../services/app-setup/app-setup.service";
 import { Field } from "./field";
-import { NgParameter, ParamRadioConfig } from "./ngparam";
+import { NgParameter, ParamRadioConfig, ParamValueMode } from "./ngparam";
 import { InputField } from "./input-field";
 import { CheckField } from "./check-field";
 import { SelectField } from "./select-field";
@@ -1117,20 +1117,39 @@ export class FormulaireDefinition extends Observable {
             this._fixVarResults.setVariableParamHeaderFromParameter(varParam, !rg);
             this._fixVarResults.setVariableResultHeaderFromParameter(computedParam);
 
-            let min: number = +varParam.minValue;
-            let max: number = +varParam.maxValue;
-            let step: number = +varParam.stepValue;
+            switch (varParam.valueMode) {
+                case ParamValueMode.MINMAX:
+                    let min: number = +varParam.minValue;
+                    let max: number = +varParam.maxValue;
+                    let step: number = +varParam.stepValue;
 
-            for (let val = min; val <= max; val += step) {
-                prms[varParam.symbol].v = val;
+                    for (let val = min; val <= max; val += step) {
+                        prms[varParam.symbol].v = val;
 
-                let res: Result = this.runNubCalc(nub, computedParam, computePrec);
-                if (res.ok) {
-                    this._fixVarResults.addVarResult(val, res.vCalc);
-                }
-                else {
-                    this._fixVarResults.addLogMessages(res.log);
-                }
+                        let res: Result = this.runNubCalc(nub, computedParam, computePrec);
+                        if (res.ok) {
+                            this._fixVarResults.addVarResult(val, res.vCalc);
+                        }
+                        else {
+                            this._fixVarResults.addLogMessages(res.log);
+                        }
+                    }
+                    break;
+
+                case ParamValueMode.LISTE:
+                    for (let val of varParam.valueList) {
+                        prms[varParam.symbol].v = val;
+
+                        let res: Result = this.runNubCalc(nub, computedParam, computePrec);
+                        if (res.ok) {
+                            this._fixVarResults.addVarResult(val, res.vCalc);
+                        }
+                        else {
+                            this._fixVarResults.addLogMessages(res.log);
+                        }
+                    }
+
+                    break;
             }
 
             this._fixVarResults.graphTitle = computedParam.symbol + " = f( " + varParam.symbol + " )";
diff --git a/src/app/formulaire/ngparam.ts b/src/app/formulaire/ngparam.ts
index 2db893c26..703ac0696 100644
--- a/src/app/formulaire/ngparam.ts
+++ b/src/app/formulaire/ngparam.ts
@@ -24,6 +24,21 @@ export enum ParamRadioConfig {
 };
 
 
+/**
+ * mode de génération des valeurs d'entrée lors d'un calcul avec plusieurs valeurs
+ */
+export enum ParamValueMode {
+    /**
+     * min, max, pas
+     */
+    MINMAX,
+
+    /**
+     * liste de valeurs discrètes
+     */
+    LISTE
+}
+
 /**
  * classe englobante de ParamDefinition (champs supplémentaires pour l'affichage, radio boutons, ...)
  */
@@ -35,6 +50,8 @@ export class NgParameter extends InputField {
     public minValue: number; // valeur min dans le cas ParamRadioConfig.VAR
     public maxValue: number; // valeur max dans le cas ParamRadioConfig.VAR
     public stepValue: number; // pas de progression dans le cas ParamRadioConfig.VAR
+    public valueList: number[];
+    public valueMode: ParamValueMode = ParamValueMode.MINMAX;
 
     constructor(private _paramDef: ParamDefinition, formId: number) {
         super(_paramDef.computeNodeType, _paramDef.symbol, formId);
diff --git a/src/index.html b/src/index.html
index 100a73f14..ec92ef2fa 100644
--- a/src/index.html
+++ b/src/index.html
@@ -14,8 +14,8 @@
   <!-- ressources pour faire fonctionner le toggler de la navbar -->
   <script src="https://code.jquery.com/jquery-3.1.1.slim.min.js" integrity="sha384-A7FZj7v+d/sdmMqp/nOQwliLvUsJfDHW+k9Omg/a/EheAdgtzNs3hpfag6Ed950n"
     crossorigin="anonymous"></script>
-  <!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/tether/1.4.0/js/tether.min.js" integrity="sha384-DztdAPBWPRXSA/3eYEEUWrWCy7G5KFbe8fFjk5JAIxUYHKkDx6Qin1DkWx51bBrb"
-    crossorigin="anonymous"></script> -->
+  <script src="https://cdnjs.cloudflare.com/ajax/libs/tether/1.4.0/js/tether.min.js" integrity="sha384-DztdAPBWPRXSA/3eYEEUWrWCy7G5KFbe8fFjk5JAIxUYHKkDx6Qin1DkWx51bBrb"
+    crossorigin="anonymous"></script>
   <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/js/bootstrap.min.js" integrity="sha384-vBWWzlZJ8ea9aCX4pEW3rVHjgjt7zpkNpZk+02D9phzyeVkE+jo0ieGizqPLForn"
     crossorigin="anonymous"></script>
 
-- 
GitLab


From d4de914c5f0508647d8d829f82a52bc2458e1d0b Mon Sep 17 00:00:00 2001
From: "francois.grand" <francois.grand@irstea.fr>
Date: Tue, 16 Jan 2018 17:47:05 +0100
Subject: [PATCH 02/10] =?UTF-8?q?ticket=20#47=20:=20ajout=20du=20r=C3=A9pe?=
 =?UTF-8?q?rtoire=20src/app/components/param-values/=20oubli=C3=A9=20dans?=
 =?UTF-8?q?=20le=20commit=20pr=C3=A9c=C3=A9dent?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../param-values/ngparam-max.component.ts     |  77 +++++
 .../param-values/ngparam-min.component.ts     |  79 +++++
 .../param-values/ngparam-step.component.ts    |  80 +++++
 .../param-values/param-values.component.html  |  24 ++
 .../param-values/param-values.component.ts    | 321 ++++++++++++++++++
 5 files changed, 581 insertions(+)
 create mode 100644 src/app/components/param-values/ngparam-max.component.ts
 create mode 100644 src/app/components/param-values/ngparam-min.component.ts
 create mode 100644 src/app/components/param-values/ngparam-step.component.ts
 create mode 100644 src/app/components/param-values/param-values.component.html
 create mode 100644 src/app/components/param-values/param-values.component.ts

diff --git a/src/app/components/param-values/ngparam-max.component.ts b/src/app/components/param-values/ngparam-max.component.ts
new file mode 100644
index 000000000..1db61f59a
--- /dev/null
+++ b/src/app/components/param-values/ngparam-max.component.ts
@@ -0,0 +1,77 @@
+import { Component, Output, EventEmitter } from "@angular/core";
+
+import { NumericalString, Pair } from "jalhyd";
+
+import { GenericInputComponent } from "../generic-input/generic-input.component";
+import { InternationalisationService } from "../../services/internationalisation/internationalisation.service";
+
+@Component({
+    selector: "ngparam-max",
+    templateUrl: "../generic-input/generic-input.component.html"
+})
+export class NgParamMaxComponent extends GenericInputComponent {
+    /**
+       * valeur actuelle du maximum
+       */
+    private _currentValue: number;
+
+    /**
+     * reférence (valeur maxi pour le maximum)
+     */
+    private _refValue: Pair;
+
+    @Output()
+    private onChange = new EventEmitter<string>();
+
+    constructor(private intlService: InternationalisationService) {
+        super();
+    }
+
+    public set refValue(v: Pair) {
+        this._refValue = v;
+    }
+
+    protected getModelValue(): any {
+        return this._currentValue;
+    }
+
+    protected setModelValue(v: any) {
+        this._currentValue = v;
+        this.onChange.emit("value");
+    }
+
+    protected validateModelValue(v: any): { isValid: boolean, message: string } {
+        let msg = undefined;
+        let valid = false;
+
+        if (!this._refValue.intervalHasValue(v))
+            msg = "La valeur n'est pas dans " + this._refValue.toString();
+        else
+            valid = true;
+
+        return { isValid: valid, message: msg };
+    }
+
+    protected modelToUI(v: any): string {
+        if (typeof (v) == "number")
+            return String(v);
+        return undefined;
+    }
+
+    protected validateUIValue(ui: string): { isValid: boolean, message: string } {
+        let valid: boolean = false;
+        let msg: string = undefined;
+
+        let v: NumericalString = new NumericalString(ui);
+        if (!v.isNumerical)
+            msg = "Veuillez entrer une valeur numérique";
+        else
+            valid = true;
+
+        return { isValid: valid, message: msg };
+    }
+
+    protected uiToModel(ui: string) {
+        return +ui;
+    }
+}
diff --git a/src/app/components/param-values/ngparam-min.component.ts b/src/app/components/param-values/ngparam-min.component.ts
new file mode 100644
index 000000000..ca6749eb4
--- /dev/null
+++ b/src/app/components/param-values/ngparam-min.component.ts
@@ -0,0 +1,79 @@
+import { Component, Output, EventEmitter } from "@angular/core";
+
+import { NumericalString, Pair } from "jalhyd";
+
+import { GenericInputComponent } from "../generic-input/generic-input.component";
+import { InternationalisationService } from "../../services/internationalisation/internationalisation.service";
+
+@Component({
+    selector: "ngparam-min",
+    templateUrl: "../generic-input/generic-input.component.html"
+})
+export class NgParamMinComponent extends GenericInputComponent {
+    /**
+     * valeur actuelle du minimum
+     */0.49999999995
+    private _currentValue: number;
+
+    /**
+     * reférence (valeur mini pour le minimum)
+     */
+    private _refValue: Pair;
+
+    @Output()
+    private onChange = new EventEmitter<string>();
+
+    public isInit: boolean;
+
+    constructor(private intlService: InternationalisationService) {
+        super();
+    }
+
+    public set refValue(v: Pair) {
+        this._refValue = v;
+    }
+
+    protected getModelValue(): any {
+        return this._currentValue;
+    }
+
+    protected setModelValue(v: any) {
+        this._currentValue = v;
+        this.onChange.emit("value");
+    }
+
+    protected validateModelValue(v: any): { isValid: boolean, message: string } {
+        let msg = undefined;
+        let valid = false;
+
+        if (!this._refValue.intervalHasValue(v))
+            msg = "La valeur n'est pas dans " + this._refValue.toString();
+        else
+            valid = true;
+
+        return { isValid: valid, message: msg };
+    }
+
+    protected modelToUI(v: any): string {
+        if (typeof (v) == "number")
+            return String(v);
+        return undefined;
+    }
+
+    protected validateUIValue(ui: string): { isValid: boolean, message: string } {
+        let valid: boolean = false;
+        let msg: string = undefined;
+
+        let v: NumericalString = new NumericalString(ui);
+        if (!v.isNumerical)
+            msg = "Veuillez entrer une valeur numérique";
+        else
+            valid = true;
+
+        return { isValid: valid, message: msg };
+    }
+
+    protected uiToModel(ui: string): any {
+        return +ui;
+    }
+}
diff --git a/src/app/components/param-values/ngparam-step.component.ts b/src/app/components/param-values/ngparam-step.component.ts
new file mode 100644
index 000000000..e34225e94
--- /dev/null
+++ b/src/app/components/param-values/ngparam-step.component.ts
@@ -0,0 +1,80 @@
+import { Component, Output, EventEmitter } from "@angular/core";
+
+import { NumericalString, Pair } from "jalhyd";
+
+import { GenericInputComponent } from "../generic-input/generic-input.component";
+import { InternationalisationService } from "../../services/internationalisation/internationalisation.service";
+
+@Component({
+    selector: "ngparam-step",
+    templateUrl: "../generic-input/generic-input.component.html"
+})
+export class NgParamStepComponent extends GenericInputComponent {
+    /**
+     * valeur actuelle du pas
+     */
+    private _currentValue: number;
+
+    /**
+     * reférence (valeur maxi pour le pas)
+     */
+    private _refValue: Pair;
+
+    @Output()
+    private onChange = new EventEmitter<string>();
+
+    constructor(private intlService: InternationalisationService) {
+        super();
+    }
+
+    public set refValue(v: Pair) {
+        this._refValue = v;
+    }
+
+    protected getModelValue(): any {
+        return this._currentValue;
+    }
+
+    protected setModelValue(v: any) {
+        this._currentValue = v;
+        this.onChange.emit("value");
+    }
+
+    protected validateModelValue(v: any): { isValid: boolean, message: string } {
+        let msg = undefined;
+        let valid = false;
+
+        if (!this._refValue.intervalHasValue(v))
+            msg = "La valeur n'est pas dans " + this._refValue.toString();
+        else {
+            valid = v > 0;
+            if (!valid)
+                msg = "La valeur ne peut pas être <= 0";
+        }
+
+        return { isValid: valid, message: msg };
+    }
+
+    protected modelToUI(v: any): string {
+        if (typeof (v) == "number")
+            return String(v);
+        return "<invalid>";
+    }
+
+    protected validateUIValue(ui: string): { isValid: boolean, message: string } {
+        let valid: boolean = false;
+        let msg: string = undefined;
+
+        let v: NumericalString = new NumericalString(ui);
+        if (!v.isNumerical)
+            msg = "Veuillez entrer une valeur numérique";
+        else
+            valid = true;
+
+        return { isValid: valid, message: msg };
+    }
+
+    protected uiToModel(ui: string) {
+        return +ui;
+    }
+}
diff --git a/src/app/components/param-values/param-values.component.html b/src/app/components/param-values/param-values.component.html
new file mode 100644
index 000000000..40b434a6e
--- /dev/null
+++ b/src/app/components/param-values/param-values.component.html
@@ -0,0 +1,24 @@
+<div class="row">
+    <div class="btn-group col-12 col-sm-3" dropdown (click)="onSelect($event)">
+        <button dropdownToggle class="btn btn-primary dropdown-toggle waves-light my-1" type="button" mdbRippleRadius>
+            {{currentLabel}}
+        </button>
+        <div class="dropdown-menu">
+            <a class="dropdown-item" *ngFor="let e of _valueModes" [value]=e.value>{{e.label}}</a>
+        </div>
+    </div>
+
+    <div *ngIf="!isList" class="col-12 col-sm-3">
+        <ngparam-min [title]="uitextValeurMini" (onChange)="onMinChanged($event)"></ngparam-min>
+    </div>
+    <div *ngIf="!isList" class="col-12 col-sm-3">
+        <ngparam-max [title]="uitextValeurMaxi" (onChange)="onMaxChanged($event)"></ngparam-max>
+    </div>
+    <div *ngIf="!isList" class="col-12 col-sm-3">
+        <ngparam-step [title]="uitextPasVariation" (onChange)="onStepChanged($event)"></ngparam-step>
+    </div>
+
+    <div *ngIf="isList" class="col-12 col-sm-9">
+        <value-list title="valeurs séparées par ';'" (onChange)="onListChanged($event)"></value-list>
+    </div>
+</div>
\ No newline at end of file
diff --git a/src/app/components/param-values/param-values.component.ts b/src/app/components/param-values/param-values.component.ts
new file mode 100644
index 000000000..46a24c045
--- /dev/null
+++ b/src/app/components/param-values/param-values.component.ts
@@ -0,0 +1,321 @@
+import { Component, Input, Output, EventEmitter, ViewChild, DoCheck } from "@angular/core";
+
+import { ParamDomainValue, Pair } from "jalhyd";
+
+import { InternationalisationService } from "../../services/internationalisation/internationalisation.service";
+import { NgParameter, ParamValueMode } from "../../formulaire/ngparam";
+import { GenericInputComponent } from "../generic-input/generic-input.component";
+import { NgParamMinComponent } from "./ngparam-min.component";
+import { NgParamMaxComponent } from "./ngparam-max.component";
+import { NgParamStepComponent } from "./ngparam-step.component";
+
+
+@Component({
+    selector: "value-list",
+    templateUrl: "../generic-input/generic-input.component.html"
+})
+export class ValueListComponent extends GenericInputComponent {
+    @Output()
+    private onChange = new EventEmitter<string>();
+
+    public _list: number[];
+
+    public isInit;
+
+    constructor(private intlService: InternationalisationService) {
+        super();
+        this._list = [];
+    }
+
+    protected getModelValue(): any {
+        return this._list;
+    }
+
+    protected setModelValue(l: any) {
+        if (typeof (l) == "number") {
+            this._list = [];
+            this._list.push(l);
+        }
+        else
+            this._list = l;
+        this.onChange.emit("value");
+    }
+
+    protected validateModelValue(v: any): { isValid: boolean, message: string } {
+        let msg = undefined;
+        let valid = false;
+
+        if (v instanceof Array) {
+            valid = true;
+            for (let e of v) {
+                valid = valid && (typeof (e) == "number")
+                if (!valid) {
+                    msg = "La valeur n'est pas une liste de nombres"
+                    break;
+                }
+            }
+        }
+
+        return { isValid: valid, message: msg };
+    }
+
+    protected modelToUI(v: any): string {
+        let res = "";
+        for (let e of v) {
+            if (res != "")
+                res += ";";
+            res += String(e);
+        }
+        return res;
+    }
+
+    protected validateUIValue(ui: string): { isValid: boolean, message: string } {
+        let valid: boolean = false;
+        let msg: string = undefined;
+
+        let tmp: string[] = ui.split(";");
+        let res = true;
+        for (let v of tmp) {
+            let isnum = v != "" && (+v == +v);
+            res = res && isnum;
+            if (!res)
+                break;
+        }
+
+        if (!res)
+            msg = "Veuillez entrer une liste de nombres";
+        else
+            valid = true;
+
+        return { isValid: valid, message: msg };
+    }
+
+    protected uiToModel(ui: string) {
+        let tmp: string[] = ui.split(";");
+        let res = [];
+        for (let v of tmp)
+            res.push(+v);
+        return res;
+    }
+}
+
+@Component({
+    selector: "param-values",
+    templateUrl: "./param-values.component.html",
+    styles: [
+        `.btn-on {
+            color:#505050;
+            border: 3px solid #505050;
+            background-color:white;
+            text-transform: uppercase;
+            font-size: 0.8em;
+        }`,
+        `.btn-off {
+            color:white;
+            border: 3px solid #505050;
+            background-color:#505050;
+            text-transform: uppercase;
+            font-size: 0.8em;
+        }`
+    ]
+})
+export class ParamValuesComponent implements DoCheck {
+    @Input("param")
+    private _param: NgParameter;
+
+    /**
+     * true si liste de valeur, false si min/max/pas
+     */
+    private _list: boolean;
+
+    private _valueModes = [];
+
+    /**
+     * composant de saisie du minimum
+     */
+    @ViewChild(NgParamMinComponent)
+    private _minComponent: NgParamMinComponent;
+
+    /**
+     * composant de saisie du maximum
+     */
+    @ViewChild(NgParamMaxComponent)
+    private _maxComponent: NgParamMaxComponent;
+
+    /**
+     * composant de saisie du pas de variation
+     */
+    @ViewChild(NgParamStepComponent)
+    private _stepComponent: NgParamStepComponent;
+
+    /**
+     * composant de saisie d'une liste de valeurs
+     */
+    @ViewChild(ValueListComponent)
+    private _listComponent: ValueListComponent;
+
+    constructor(private intlService: InternationalisationService) {
+        this._valueModes.push({ "value": ParamValueMode.MINMAX, "label": "Min/max" });
+        this._valueModes.push({ "value": ParamValueMode.LISTE, "label": "Liste" });
+    }
+
+    private getDefaultMin(): number {
+        switch (this._param.domain.domain) {
+            case ParamDomainValue.ANY:
+            case ParamDomainValue.NOT_NULL:
+                return -10;
+
+            default:
+                return this._param.domain.minValue;
+        }
+    }
+
+    private getDefaultMax(): number {
+        switch (this._param.domain.domain) {
+            case ParamDomainValue.INTERVAL:
+                return this._param.domain.maxValue;
+
+            default:
+                return 10;
+        }
+    }
+
+    private initMinMaxStep() {
+        // valeur pour min (celle déjà définie ou celle déduite du domaine de définition)
+        let min: number = this._param.minValue;
+        let ok = min != undefined
+        if (ok) {
+            try {
+                // on la vérifie
+                this._param.checkValue(min);
+                ok = true;
+            }
+            catch (e) {
+                ok = false;
+            }
+        }
+        if (!ok)
+            min = this.getDefaultMin();
+
+        // valeur pour max (celle déjà définie ou celle déduite du domaine de définition)
+        let max: number = this._param.maxValue;
+        ok = max != undefined
+        if (ok) {
+            try {
+                // on la vérifie
+                this._param.checkValue(max);
+                ok = true;
+            }
+            catch (e) {
+                ok = false;
+            }
+        }
+        if (!ok)
+            min = this.getDefaultMax();
+
+        this._minComponent.refValue = new Pair(this._param.domain.minValue, max);
+        this._minComponent.model = min;
+
+        this._maxComponent.refValue = new Pair(min, this._param.domain.maxValue);
+        this._maxComponent.model = max;
+
+        this.updateStepComponentRef();
+
+        let step = this._param.stepValue;
+        if (step == undefined)
+            step = (max - min) / 20;
+        if (min == -Infinity || max == Infinity)
+            step = 10;
+        this._stepComponent.model = step;
+    }
+
+    private onMinChanged(val: string) {
+        this.updateStepComponentRef();
+
+        this._maxComponent.refValue = new Pair(this._minComponent.model, this._param.domain.maxValue);
+        this._maxComponent.validateModel();
+
+        if (this._minComponent.validateModel())
+            this._param.minValue = this._minComponent.model;
+    }
+
+    private onMaxChanged(val: string) {
+        this.updateStepComponentRef();
+
+        this._minComponent.refValue = new Pair(this._param.domain.minValue, this._maxComponent.model);
+        this._minComponent.validateModel();
+
+        if (this._maxComponent.validateModel())
+            this._param.maxValue = this._maxComponent.model;
+    }
+
+    private onStepChanged(val: string) {
+        if (this._stepComponent.validateModel())
+            this._param.stepValue = this._stepComponent.model;
+    }
+
+    private onListChanged(val: string) {
+        if (this._listComponent.validateModel())
+            this._param.valueList = this._listComponent.model;
+    }
+
+    public ngDoCheck() {
+        // initialisation des champs min/max/step à l'apparition de ces contrôles
+        if (this._minComponent != undefined && !this._minComponent.isInit) {
+            this._minComponent.isInit = true;
+            this.initMinMaxStep();
+        }
+
+        if (this._listComponent != undefined && !this._listComponent.isInit) {
+            this._listComponent.isInit = true;
+
+            this._listComponent.model = [];
+            if (this._param.isDefined)
+                this._listComponent.model.push(this._param.getValue());
+        }
+    }
+
+    /**
+     * met à jour la valeur de référence du composant gérant le pas de variation
+     */
+    private updateStepComponentRef() {
+        this._stepComponent.refValue = new Pair(1e-9, this._maxComponent.model - this._minComponent.model);
+        this._stepComponent.validateModel();
+    }
+
+    private get uitextValeurMini() {
+        return this.intlService.localizeText("INFO_PARAMFIELD_VALEURMINI");
+    }
+
+    private get uitextValeurMaxi() {
+        return this.intlService.localizeText("INFO_PARAMFIELD_VALEURMAXI");
+    }
+
+    private get uitextPasVariation() {
+        return this.intlService.localizeText("INFO_PARAMFIELD_PASVARIATION");
+    }
+
+    private get isList(): boolean {
+        return this._param.valueMode == ParamValueMode.LISTE;
+    }
+
+    /**
+     * valeur courante affichée dans le select
+     */
+    private get currentLabel(): string {
+        // return this._list ? "Liste" : "Min/max/pas";
+        return ParamValueMode[this._param.valueMode];
+    }
+
+    private onSelect(event: any) {
+        // for (let a of event.target.attributes)
+        //     if (a.name == "value") {
+        //         var val = a.value;
+        //         break;
+        //     }
+
+        // // this._currentLabel = event.target.text;
+        // this._list = val == "list";
+        this._param.valueMode = event.target.value;
+    }
+}
-- 
GitLab


From 3918fda01856567e744baf35415d17f9372d5c58 Mon Sep 17 00:00:00 2001
From: "francois.grand" <francois.grand@irstea.fr>
Date: Tue, 16 Jan 2018 18:53:40 +0100
Subject: [PATCH 03/10] =?UTF-8?q?ticket=20#47=20:=20param=C3=A8tre=20?=
 =?UTF-8?q?=C3=A0=20varier=20:=20ajout=20d'une=20coche=20"histogramme"=20p?=
 =?UTF-8?q?our=20tracer=20un=20histogramme=20plut=C3=B4t=20qu'un=20graphe?=
 =?UTF-8?q?=20XY=20(liste=20de=20valeurs)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../fixedvar-results.component.ts             | 91 ++++++++++++++++++-
 .../param-values/param-values.component.html  |  9 +-
 .../param-values/param-values.component.ts    | 11 +--
 src/app/formulaire/formulaire-definition.ts   |  6 +-
 src/app/formulaire/ngparam.ts                 |  1 +
 src/app/results/fixed-var-results.ts          | 25 +++++
 6 files changed, 125 insertions(+), 18 deletions(-)

diff --git a/src/app/components/fixedvar-results/fixedvar-results.component.ts b/src/app/components/fixedvar-results/fixedvar-results.component.ts
index 802f66825..f1774af39 100644
--- a/src/app/components/fixedvar-results/fixedvar-results.component.ts
+++ b/src/app/components/fixedvar-results/fixedvar-results.component.ts
@@ -4,7 +4,7 @@ import { InternationalisationService } from "../../services/internationalisation
 import { ApplicationSetupService } from '../../services/app-setup/app-setup.service';
 import { LogComponent } from '../../components/log/log.component';
 import { cLog } from "jalhyd";
-import { FixedVarResults } from "../../results/fixed-var-results";
+import { FixedVarResults, GraphType } from "../../results/fixed-var-results";
 
 @Component({
     selector: "fixedvar-results",
@@ -48,7 +48,7 @@ export class FixedVarResultsComponent {
     /*
     * config du graphe
     */
-    private graph_type = "line";
+    private graph_type: string;
     private graph_data = {};
     private graph_options = {
         responsive: true,
@@ -62,7 +62,8 @@ export class FixedVarResultsComponent {
         title: {
             display: true,
             text: ""
-        }
+        },
+        scales: {}
     };
 
     /**
@@ -102,7 +103,23 @@ export class FixedVarResultsComponent {
             this._varResults.push({ "param": r["param"].toFixed(nDigits), "result": r["result"].toFixed(nDigits) });
 
         this.logComponent.log = this._results.log;
-        this.generateGraph();
+
+        switch (this._results.graphType) {
+            case GraphType.Histogram:
+                this.graph_type = "bar";
+                this.generateBarGraph();
+                break;
+
+            case GraphType.HistoLine:
+                this.graph_type = "line";
+                this.generateLineGraph();
+                break;
+
+            default:
+                this.graph_type = "scatter";
+                this.generateScatterGraph();
+                break;
+        }
     }
     /**
      * affichage de la table des résultats fixés
@@ -139,7 +156,35 @@ export class FixedVarResultsComponent {
     //     this.logComponent.addLogEntries(l);
     // }
 
-    private generateGraph() {
+    /**
+     * génère les données d'un graphe de type "line"
+     */
+    private generateLineGraph() {
+        let labs = [];
+        let dat = [];
+        for (let i in this._results.varResults) {
+            let r = this._results.varResults[i];
+            labs.push(r["param"]);
+            dat.push(this._results.varGraph[i]);
+        }
+
+        this.graph_options.title.text = this._results.graphTitle;
+
+        this.graph_data = {
+            labels: labs,
+            datasets: [
+                {
+                    label: "",
+                    data: dat
+                }
+            ]
+        };
+    }
+
+    /**
+     * génère les données d'un graphe de type "bar"
+     */
+    private generateBarGraph() {
         let labs = [];
         let dat = [];
         for (let i in this._results.varResults) {
@@ -149,6 +194,13 @@ export class FixedVarResultsComponent {
         }
 
         this.graph_options.title.text = this._results.graphTitle;
+        this.graph_options.scales = {
+            xAxes: [{
+                gridLines: {
+                    offsetGridLines: true
+                }
+            }]
+        };
 
         this.graph_data = {
             labels: labs,
@@ -161,6 +213,35 @@ export class FixedVarResultsComponent {
         };
     }
 
+    /**
+     * génère les données d'un graphe de type "scatter"
+     */
+    private generateScatterGraph() {
+        let dat = [];
+        for (let i in this._results.varResults) {
+            let r = this._results.varResults[i];
+            dat.push({ x: r["param"], y: this._results.varGraph[i] });
+
+        }
+
+        this.graph_options.title.text = this._results.graphTitle;
+        this.graph_options.scales = {
+            xAxes: [{
+                type: 'linear',
+                position: 'bottom'
+            }]
+        };
+
+        this.graph_data = {
+            datasets: [
+                {
+                    label: "",
+                    data: dat
+                }
+            ]
+        };
+    }
+
     // public reset(fixed: boolean) {
     //     this._results.reset();
     //     this.logComponent.reset();
diff --git a/src/app/components/param-values/param-values.component.html b/src/app/components/param-values/param-values.component.html
index 40b434a6e..231911877 100644
--- a/src/app/components/param-values/param-values.component.html
+++ b/src/app/components/param-values/param-values.component.html
@@ -1,5 +1,5 @@
 <div class="row">
-    <div class="btn-group col-12 col-sm-3" dropdown (click)="onSelect($event)">
+    <div class="btn-group col-12 col-sm-3" dropdown (click)="onSelectValueMode($event)">
         <button dropdownToggle class="btn btn-primary dropdown-toggle waves-light my-1" type="button" mdbRippleRadius>
             {{currentLabel}}
         </button>
@@ -18,7 +18,12 @@
         <ngparam-step [title]="uitextPasVariation" (onChange)="onStepChanged($event)"></ngparam-step>
     </div>
 
-    <div *ngIf="isList" class="col-12 col-sm-9">
+    <div *ngIf="isList" class="col-12 col-sm-6">
         <value-list title="valeurs séparées par ';'" (onChange)="onListChanged($event)"></value-list>
     </div>
+
+    <div *ngIf="isList" class="col-12 col-sm-3">
+        <input type="checkbox" name="histogram" [(ngModel)]="_param.histogramMode">Histogramme
+        <br/>
+    </div>
 </div>
\ No newline at end of file
diff --git a/src/app/components/param-values/param-values.component.ts b/src/app/components/param-values/param-values.component.ts
index 46a24c045..5bfea4209 100644
--- a/src/app/components/param-values/param-values.component.ts
+++ b/src/app/components/param-values/param-values.component.ts
@@ -303,19 +303,10 @@ export class ParamValuesComponent implements DoCheck {
      * valeur courante affichée dans le select
      */
     private get currentLabel(): string {
-        // return this._list ? "Liste" : "Min/max/pas";
         return ParamValueMode[this._param.valueMode];
     }
 
-    private onSelect(event: any) {
-        // for (let a of event.target.attributes)
-        //     if (a.name == "value") {
-        //         var val = a.value;
-        //         break;
-        //     }
-
-        // // this._currentLabel = event.target.text;
-        // this._list = val == "list";
+    private onSelectValueMode(event: any) {
         this._param.valueMode = event.target.value;
     }
 }
diff --git a/src/app/formulaire/formulaire-definition.ts b/src/app/formulaire/formulaire-definition.ts
index fc847e626..a83a91287 100644
--- a/src/app/formulaire/formulaire-definition.ts
+++ b/src/app/formulaire/formulaire-definition.ts
@@ -19,7 +19,7 @@ import { FormulaireElement } from "./formulaire-element";
 import { ValueDependency } from "./value-dependency";
 import { ValueDependencyCondition } from "./value-dependency-condition";
 import { ExistenceDependency } from "./existence-dependency";
-import { FixedVarResults } from "../results/fixed-var-results";
+import { FixedVarResults, GraphType } from "../results/fixed-var-results";
 import { SectionResults } from "../results/section-results";
 import { RemousResults } from "../results/remous-results";
 import { StringMap } from "../stringmap";
@@ -1119,6 +1119,8 @@ export class FormulaireDefinition extends Observable {
 
             switch (varParam.valueMode) {
                 case ParamValueMode.MINMAX:
+                    this._fixVarResults.graphType = GraphType.Scatter;
+
                     let min: number = +varParam.minValue;
                     let max: number = +varParam.maxValue;
                     let step: number = +varParam.stepValue;
@@ -1137,6 +1139,8 @@ export class FormulaireDefinition extends Observable {
                     break;
 
                 case ParamValueMode.LISTE:
+                    this._fixVarResults.graphType = varParam.histogramMode ? GraphType.Histogram : GraphType.Scatter;
+
                     for (let val of varParam.valueList) {
                         prms[varParam.symbol].v = val;
 
diff --git a/src/app/formulaire/ngparam.ts b/src/app/formulaire/ngparam.ts
index 703ac0696..a662906de 100644
--- a/src/app/formulaire/ngparam.ts
+++ b/src/app/formulaire/ngparam.ts
@@ -52,6 +52,7 @@ export class NgParameter extends InputField {
     public stepValue: number; // pas de progression dans le cas ParamRadioConfig.VAR
     public valueList: number[];
     public valueMode: ParamValueMode = ParamValueMode.MINMAX;
+    public histogramMode: boolean = false; // A VIRER et deplacer dans FixVarResults
 
     constructor(private _paramDef: ParamDefinition, formId: number) {
         super(_paramDef.computeNodeType, _paramDef.symbol, formId);
diff --git a/src/app/results/fixed-var-results.ts b/src/app/results/fixed-var-results.ts
index 33b49bb07..97d16be54 100644
--- a/src/app/results/fixed-var-results.ts
+++ b/src/app/results/fixed-var-results.ts
@@ -3,6 +3,26 @@ import { cLog } from "jalhyd";
 import { NgParameter } from "../formulaire/ngparam";
 import { CalculatorResults } from "./calculator-results";
 
+/**
+ * type de graphe
+ */
+export enum GraphType {
+    /**
+     * histogramme
+     */
+    Histogram,
+
+    /**
+     * points indépendants reliés par une courbe
+     */
+    HistoLine,
+
+    /**
+     * graphe XY classique
+     */
+    Scatter,
+}
+
 export class FixedVarResults extends CalculatorResults {
     /**
      * résultats fixed (true) ou variés (false)
@@ -34,6 +54,11 @@ export class FixedVarResults extends CalculatorResults {
      */
     private _graphTitle: string;
 
+    /**
+     * type de graphe
+     */
+    public graphType: GraphType = GraphType.Scatter;
+
     /**
      * tableau de valeurs du graphe des résultats variés
      */
-- 
GitLab


From b62242ebecc9e2213343e5d1f9c147087b26d89c Mon Sep 17 00:00:00 2001
From: "francois.grand" <francois.grand@irstea.fr>
Date: Thu, 18 Jan 2018 16:11:26 +0100
Subject: [PATCH 04/10] =?UTF-8?q?ticket=20#47=20:=20corrige=20"initialiser?=
 =?UTF-8?q?=20les=20valeurs=20min/max=20=C3=A0=20la=20moiti=C3=A9=20et=20a?=
 =?UTF-8?q?u=20double=20de=20la=20valeur=20existante=20du=20param=C3=A8tre?=
 =?UTF-8?q?,=20initialiser=20le=20pas=20=C3=A0=20(max-min)/20"?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../param-values/param-values.component.ts    | 13 +++-----
 src/app/formulaire/ngparam.ts                 | 30 -------------------
 2 files changed, 4 insertions(+), 39 deletions(-)

diff --git a/src/app/components/param-values/param-values.component.ts b/src/app/components/param-values/param-values.component.ts
index 5bfea4209..0349075f1 100644
--- a/src/app/components/param-values/param-values.component.ts
+++ b/src/app/components/param-values/param-values.component.ts
@@ -211,22 +211,17 @@ export class ParamValuesComponent implements DoCheck {
             }
         }
         if (!ok)
-            min = this.getDefaultMax();
+            max = this.getDefaultMax();
 
         this._minComponent.refValue = new Pair(this._param.domain.minValue, max);
-        this._minComponent.model = min;
+        this._minComponent.model = this._param.getValue() / 2;
 
         this._maxComponent.refValue = new Pair(min, this._param.domain.maxValue);
-        this._maxComponent.model = max;
+        this._maxComponent.model = this._param.getValue() * 2;
 
         this.updateStepComponentRef();
 
-        let step = this._param.stepValue;
-        if (step == undefined)
-            step = (max - min) / 20;
-        if (min == -Infinity || max == Infinity)
-            step = 10;
-        this._stepComponent.model = step;
+        this._stepComponent.model = (this._maxComponent.model - this._minComponent.model) / 20;
     }
 
     private onMinChanged(val: string) {
diff --git a/src/app/formulaire/ngparam.ts b/src/app/formulaire/ngparam.ts
index a662906de..16dd165eb 100644
--- a/src/app/formulaire/ngparam.ts
+++ b/src/app/formulaire/ngparam.ts
@@ -56,32 +56,6 @@ export class NgParameter extends InputField {
 
     constructor(private _paramDef: ParamDefinition, formId: number) {
         super(_paramDef.computeNodeType, _paramDef.symbol, formId);
-        switch (this._paramDef.getDomain().domain) {
-            case ParamDomainValue.ANY:
-                this.minValue = -10;
-                this.maxValue = 10;
-                this.stepValue = 0.5;
-                break;
-
-            case ParamDomainValue.POS:
-            case ParamDomainValue.NOT_NULL:
-                this.minValue = 0.01;
-                this.maxValue = 10;
-                this.stepValue = 0.5;
-                break;
-
-            case ParamDomainValue.INTERVAL:
-                this.minValue = this._paramDef.getDomain().minValue;
-                this.maxValue = this._paramDef.getDomain().maxValue;
-                this.stepValue = (this.maxValue - this.minValue) / 10;
-                break;
-
-            case ParamDomainValue.POS_NULL:
-                this.minValue = 0;
-                this.maxValue = 10;
-                this.stepValue = 0.5;
-                break;
-        }
     }
 
     get symbol(): string {
@@ -92,10 +66,6 @@ export class NgParameter extends InputField {
         return this._paramDef.getDomain();
     }
 
-    // get alias(): string {
-    //     return this._paramDef.symbolAlias;
-    // }
-
     public getValue() {
         return this._paramDef.v;
     }
-- 
GitLab


From 30e391067e6f3e0a132c71d04cd1f41f58957860 Mon Sep 17 00:00:00 2001
From: "francois.grand" <francois.grand@irstea.fr>
Date: Thu, 18 Jan 2018 16:19:43 +0100
Subject: [PATCH 05/10] =?UTF-8?q?ticket=20#47=20:=20points=20du=20graph=20?=
 =?UTF-8?q?XY=20(param=C3=A8tre=20=C3=A0=20varier)=20trac=C3=A9s=20en=20no?=
 =?UTF-8?q?ir=20plut=C3=B4t=20qu'en=20gris?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../components/fixedvar-results/fixedvar-results.component.ts | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/src/app/components/fixedvar-results/fixedvar-results.component.ts b/src/app/components/fixedvar-results/fixedvar-results.component.ts
index f1774af39..890766abc 100644
--- a/src/app/components/fixedvar-results/fixedvar-results.component.ts
+++ b/src/app/components/fixedvar-results/fixedvar-results.component.ts
@@ -236,7 +236,9 @@ export class FixedVarResultsComponent {
             datasets: [
                 {
                     label: "",
-                    data: dat
+                    data: dat,
+                    borderColor: '#000000',
+                    backgroundColor: '#000000'
                 }
             ]
         };
-- 
GitLab


From a486f542703306e2bbfdd428247b6ef6217bcf5f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois?= <francois.grand@irstea.fr>
Date: Fri, 19 Jan 2018 07:05:05 +0100
Subject: [PATCH 06/10] =?UTF-8?q?ticket=20#47=20:=20extraction=20d'un=20co?=
 =?UTF-8?q?mposant=20d'affichage=20du=20graphe=20des=20r=C3=A9sultats=20Re?=
 =?UTF-8?q?sultsGraphComponent?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/app/app.module.ts                         |   5 +-
 .../fixedvar-results.component.html           |   7 +-
 .../fixedvar-results.component.ts             | 226 +++---------------
 .../results-graph.component.html              |   6 +
 .../results-graph/results-graph.component.ts  | 160 +++++++++++++
 5 files changed, 204 insertions(+), 200 deletions(-)
 create mode 100644 src/app/components/results-graph/results-graph.component.html
 create mode 100644 src/app/components/results-graph/results-graph.component.ts

diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index cdec1aedb..545d930ee 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -32,6 +32,7 @@ import { GenericCalculatorComponent } from './components/generic-calculator/calc
 import { CalcCanvasComponent } from './components/canvas/canvas.component';
 import { SectionCanvasComponent } from './components/section-canvas/section-canvas.component';
 import { RemousResultsComponent } from './components/remous-results/remous-results.component';
+import { ResultsGraphComponent } from './components/results-graph/results-graph.component';
 import { LogComponent } from './components/log/log.component';
 import { CalculatorListComponent } from './components/calculator-list/calculator-list.component';
 import { ApplicationSetupComponent } from './components/app-setup/app-setup.component';
@@ -66,7 +67,7 @@ const appRoutes: Routes = [
     NgParamInputComponent,
     FieldSetComponent,
     ParamFieldLineComponent, NgParamMinComponent, NgParamMaxComponent, NgParamStepComponent,
-    ParamValuesComponent, ValueListComponent, 
+    ParamValuesComponent, ValueListComponent,
     SelectFieldLineComponent, CheckFieldLineComponent,
     LogComponent,
     CalculatorListComponent,
@@ -74,7 +75,7 @@ const appRoutes: Routes = [
     BaseParamInputComponent,
     GenericCalculatorComponent,
     // AlertDialog,
-    CalculatorResultsComponent, FixedVarResultsComponent, SectionResultsComponent, RemousResultsComponent,
+    CalculatorResultsComponent, FixedVarResultsComponent, SectionResultsComponent, RemousResultsComponent, ResultsGraphComponent,
     CalcCanvasComponent, SectionCanvasComponent
   ],
   // entryComponents: [AlertDialog],
diff --git a/src/app/components/fixedvar-results/fixedvar-results.component.html b/src/app/components/fixedvar-results/fixedvar-results.component.html
index c9b33f435..f17d9e8eb 100644
--- a/src/app/components/fixedvar-results/fixedvar-results.component.html
+++ b/src/app/components/fixedvar-results/fixedvar-results.component.html
@@ -4,12 +4,7 @@
     </div>
 </div>
 
-<div class="row">
-    <div class="col-8 mx-auto">
-        <chart *ngIf="showVarResults" [type]="graph_type" [data]="graph_data" [options]="graph_options">
-        </chart>
-    </div>
-</div>
+<results-graph *ngIf="showVarResults"></results-graph>
 
 <!-- 
     classe conditionnelle :
diff --git a/src/app/components/fixedvar-results/fixedvar-results.component.ts b/src/app/components/fixedvar-results/fixedvar-results.component.ts
index 890766abc..27b225369 100644
--- a/src/app/components/fixedvar-results/fixedvar-results.component.ts
+++ b/src/app/components/fixedvar-results/fixedvar-results.component.ts
@@ -1,10 +1,10 @@
-import { Component, ViewChild } from "@angular/core";
+import { Component, ViewChild, DoCheck } from "@angular/core";
 
 import { InternationalisationService } from "../../services/internationalisation/internationalisation.service";
 import { ApplicationSetupService } from '../../services/app-setup/app-setup.service';
 import { LogComponent } from '../../components/log/log.component';
-import { cLog } from "jalhyd";
-import { FixedVarResults, GraphType } from "../../results/fixed-var-results";
+import { FixedVarResults } from "../../results/fixed-var-results";
+import { ResultsGraphComponent } from "../results-graph/results-graph.component";
 
 @Component({
     selector: "fixedvar-results",
@@ -29,7 +29,7 @@ import { FixedVarResults, GraphType } from "../../results/fixed-var-results";
     `
     ]
 })
-export class FixedVarResultsComponent {
+export class FixedVarResultsComponent implements DoCheck {
     /**
      * résultats non mis en forme
      */
@@ -45,26 +45,10 @@ export class FixedVarResultsComponent {
      */
     private _varResults: Object[];
 
-    /*
-    * config du graphe
-    */
-    private graph_type: string;
-    private graph_data = {};
-    private graph_options = {
-        responsive: true,
-        maintainAspectRatio: true,
-        animation: {
-            duration: 0
-        },
-        legend: {
-            display: false
-        },
-        title: {
-            display: true,
-            text: ""
-        },
-        scales: {}
-    };
+    /**
+     * true si le graphe des résultats doit être remis à jour
+     */
+    private _updateResultsGraph: boolean;
 
     /**
      * composant journal
@@ -72,6 +56,9 @@ export class FixedVarResultsComponent {
     @ViewChild(LogComponent)
     private logComponent: LogComponent;
 
+    @ViewChild(ResultsGraphComponent)
+    private resultsGraphComponent: ResultsGraphComponent;
+
     constructor(
         private intlService: InternationalisationService,
         private appSetupService: ApplicationSetupService
@@ -79,48 +66,44 @@ export class FixedVarResultsComponent {
 
     public set results(r: FixedVarResults) {
         this._results = r;
-        this.updateView();
+        this._updateResultsGraph = true;
     }
 
     public updateView() {
         this._fixedResults = [];
         this._varResults = [];
         this.logComponent.log = undefined;
-        if (this._results != undefined)
-            this.generateResults();
+        this.generateResults();
+        this._updateResultsGraph = true;
     }
 
-    private generateResults() {
-        const nDigits = this.appSetupService.displayDigits;
-        const prec = this.appSetupService.displayPrecision;
-
-        for (let r of this._results.fixedResults) {
-            let v = r["value"];
-            this._fixedResults.push({ "label": r["label"], "value": v.toFixed(nDigits) });
+    public ngDoCheck() {
+        if (this._updateResultsGraph) {
+            if (this.resultsGraphComponent != undefined) {
+                this.resultsGraphComponent.results = this._results;
+                this.resultsGraphComponent.updateView();
+                this._updateResultsGraph = false;
+            }
         }
+    }
 
-        for (let r of this._results.varResults)
-            this._varResults.push({ "param": r["param"].toFixed(nDigits), "result": r["result"].toFixed(nDigits) });
-
-        this.logComponent.log = this._results.log;
+    private generateResults() {
+        if (this._results != undefined) {
+            const nDigits = this.appSetupService.displayDigits;
+            const prec = this.appSetupService.displayPrecision;
 
-        switch (this._results.graphType) {
-            case GraphType.Histogram:
-                this.graph_type = "bar";
-                this.generateBarGraph();
-                break;
+            for (let r of this._results.fixedResults) {
+                let v = r["value"];
+                this._fixedResults.push({ "label": r["label"], "value": v.toFixed(nDigits) });
+            }
 
-            case GraphType.HistoLine:
-                this.graph_type = "line";
-                this.generateLineGraph();
-                break;
+            for (let r of this._results.varResults)
+                this._varResults.push({ "param": r["param"].toFixed(nDigits), "result": r["result"].toFixed(nDigits) });
 
-            default:
-                this.graph_type = "scatter";
-                this.generateScatterGraph();
-                break;
+            this.logComponent.log = this._results.log;
         }
     }
+
     /**
      * affichage de la table des résultats fixés
      */
@@ -143,147 +126,6 @@ export class FixedVarResultsComponent {
         return this.intlService.localizeText("INFO_CALCULATOR_VALEURS");
     }
 
-    // public addFixedResult(p: NgParameter, v: number, fixedPrec: number, displaySymbol: boolean) {
-    //     this._fixedResults.push({ "label": this.paramLabel(p, displaySymbol), "value": v.toFixed(fixedPrec) });
-    // }
-
-    // public addVarResult(paramVal: number, resVal: number, fixedPrec: number) {
-    //     this._varResults.push({ "param": paramVal.toFixed(fixedPrec), "result": resVal.toFixed(fixedPrec) });
-    //     this._varGraph.push(resVal);
-    // }
-
-    // public addLogMessages(l: cLog) {
-    //     this.logComponent.addLogEntries(l);
-    // }
-
-    /**
-     * génère les données d'un graphe de type "line"
-     */
-    private generateLineGraph() {
-        let labs = [];
-        let dat = [];
-        for (let i in this._results.varResults) {
-            let r = this._results.varResults[i];
-            labs.push(r["param"]);
-            dat.push(this._results.varGraph[i]);
-        }
-
-        this.graph_options.title.text = this._results.graphTitle;
-
-        this.graph_data = {
-            labels: labs,
-            datasets: [
-                {
-                    label: "",
-                    data: dat
-                }
-            ]
-        };
-    }
-
-    /**
-     * génère les données d'un graphe de type "bar"
-     */
-    private generateBarGraph() {
-        let labs = [];
-        let dat = [];
-        for (let i in this._results.varResults) {
-            let r = this._results.varResults[i];
-            labs.push(r["param"]);
-            dat.push(this._results.varGraph[i]);
-        }
-
-        this.graph_options.title.text = this._results.graphTitle;
-        this.graph_options.scales = {
-            xAxes: [{
-                gridLines: {
-                    offsetGridLines: true
-                }
-            }]
-        };
-
-        this.graph_data = {
-            labels: labs,
-            datasets: [
-                {
-                    label: "",
-                    data: dat
-                }
-            ]
-        };
-    }
-
-    /**
-     * génère les données d'un graphe de type "scatter"
-     */
-    private generateScatterGraph() {
-        let dat = [];
-        for (let i in this._results.varResults) {
-            let r = this._results.varResults[i];
-            dat.push({ x: r["param"], y: this._results.varGraph[i] });
-
-        }
-
-        this.graph_options.title.text = this._results.graphTitle;
-        this.graph_options.scales = {
-            xAxes: [{
-                type: 'linear',
-                position: 'bottom'
-            }]
-        };
-
-        this.graph_data = {
-            datasets: [
-                {
-                    label: "",
-                    data: dat,
-                    borderColor: '#000000',
-                    backgroundColor: '#000000'
-                }
-            ]
-        };
-    }
-
-    // public reset(fixed: boolean) {
-    //     this._results.reset();
-    //     this.logComponent.reset();
-    // }
-
-    // public setVariableParamHeader(h: string) {
-    //     this._variableParamHeader = h;
-    // }
-
-    // public setVariableParamHeaderFromParameter(p: NgParameter, displaySymbol: boolean) {
-    //     this._variableParamHeader = this.paramLabel(p, displaySymbol);
-    // }
-
-    // public setVariableResultHeader(h: string) {
-    //     this._variableResultHeader = h;
-    // }
-
-    // public setVariableResultHeaderFromParameter(p: NgParameter) {
-    //     this._variableResultHeader = this.paramLabel(p, true);
-    // }
-
-    // public setGraphTitle(t: string) {
-    //     this.graph_options.title.text = t;
-    // }
-
-    // private paramLabel(p: NgParameter, displaySymbol: boolean): string {
-    //     let res = "";
-    //     if (displaySymbol)
-    //         res += p.symbol;
-    //     if (p.label != undefined && p.label != "")
-    //         if (p.symbol != p.label || !displaySymbol) {
-    //             if (res.length > 0)
-    //                 res += ":";
-    //             res += p.label;
-    //         }
-    //     if (p.unit != undefined && p.unit != "")
-    //         res += " (" + p.unit + ")";
-    //     return res;
-    // }
-
     private getFixedResultClass(i: number) {
         if (this._results.isFixed && i == this._results.fixedResults.length - 1)
             return "font-weight-bold";
diff --git a/src/app/components/results-graph/results-graph.component.html b/src/app/components/results-graph/results-graph.component.html
new file mode 100644
index 000000000..b34ec9a0d
--- /dev/null
+++ b/src/app/components/results-graph/results-graph.component.html
@@ -0,0 +1,6 @@
+<div class="row">
+    <div class="col-12">
+        <chart [type]="graph_type" [data]="graph_data" [options]="graph_options">
+        </chart>
+    </div>
+</div>
\ No newline at end of file
diff --git a/src/app/components/results-graph/results-graph.component.ts b/src/app/components/results-graph/results-graph.component.ts
new file mode 100644
index 000000000..bc85c2a18
--- /dev/null
+++ b/src/app/components/results-graph/results-graph.component.ts
@@ -0,0 +1,160 @@
+import { Component, AfterViewInit, EventEmitter, Output } from '@angular/core';
+
+import { FixedVarResults, GraphType } from "../../results/fixed-var-results";
+
+@Component({
+    selector: 'results-graph',
+    templateUrl: './results-graph.component.html'
+})
+export class ResultsGraphComponent { //implements AfterViewInit {
+    private _results: FixedVarResults;
+
+    /*
+     * config du graphe
+     */
+    private graph_type: string;
+    private graph_data = {};
+    private graph_options = {
+        responsive: true,
+        maintainAspectRatio: true,
+        animation: {
+            duration: 0
+        },
+        legend: {
+            display: false
+        },
+        title: {
+            display: true,
+            text: ""
+        }
+        // scales: {}
+    };
+
+    /**
+     * événement émis à la fin de la création de la vue
+     */
+    // @Output()
+    // private onViewInit = new EventEmitter();
+
+    public set results(r: FixedVarResults) {
+        this._results = r;
+        // this.updateView();
+    }
+
+    // http://www.chartjs.org/docs/latest/charts/line.html#dataset-properties
+    //     showLine
+
+    public updateView() {
+        switch (this._results.graphType) {
+            case GraphType.Histogram:
+                this.graph_type = "bar";
+                this.generateBarGraph();
+                break;
+
+            case GraphType.HistoLine:
+                this.graph_type = "line";
+                this.generateLineGraph();
+                break;
+
+            default:
+                this.graph_type = "scatter";
+                this.generateScatterGraph();
+                break;
+        }
+    }
+
+    // public ngAfterViewInit() {
+    //     this.onViewInit.emit();
+    // }
+
+    /**
+     * génère les données d'un graphe de type "line"
+     */
+    private generateLineGraph() {
+        let labs = [];
+        let dat = [];
+        for (let i in this._results.varResults) {
+            let r = this._results.varResults[i];
+            labs.push(r["param"]);
+            dat.push(this._results.varGraph[i]);
+        }
+
+        this.graph_options.title.text = this._results.graphTitle;
+
+        this.graph_data = {
+            labels: labs,
+            datasets: [
+                {
+                    label: "",
+                    data: dat
+                }
+            ]
+        };
+    }
+
+    /**
+     * génère les données d'un graphe de type "bar"
+     */
+    private generateBarGraph() {
+        let labs = [];
+        let dat = [];
+        for (let i in this._results.varResults) {
+            let r = this._results.varResults[i];
+            labs.push(r["param"]);
+            dat.push(this._results.varGraph[i]);
+        }
+
+        this.graph_options.title.text = this._results.graphTitle;
+        this.graph_options["scales"] = {
+            xAxes: [{
+                gridLines: {
+                    offsetGridLines: true
+                }
+            }]
+        };
+
+        this.graph_data = {
+            labels: labs,
+            datasets: [
+                {
+                    label: "",
+                    data: dat
+                }
+            ]
+        };
+    }
+
+    /**
+     * génère les données d'un graphe de type "scatter"
+     */
+    private generateScatterGraph() {
+        let dat = [];
+        for (let i in this._results.varResults) {
+            let r = this._results.varResults[i];
+            dat.push({ x: r["param"], y: this._results.varGraph[i] });
+        }
+
+        this.graph_options.title.text = this._results.graphTitle;
+        this.graph_options["scales"] = {
+            xAxes: [{
+                type: 'linear',
+                position: 'bottom'
+            }],
+            yAxes: [{
+                type: 'linear',
+                position: 'left'
+            }]
+        };
+
+        this.graph_data = {
+            datasets: [
+                {
+                    label: "",
+                    data: dat,
+                    // borderColor: '#000000',
+                    // backgroundColor: '#000000'
+                }
+            ]
+        };
+    }
+}
\ No newline at end of file
-- 
GitLab


From 6e6a2bf5b3382d2e77ec15e19a3fd974cd22ae19 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois?= <francois.grand@irstea.fr>
Date: Fri, 19 Jan 2018 07:08:48 +0100
Subject: [PATCH 07/10] =?UTF-8?q?Correction=20d'un=20bug=20d'initialisatio?=
 =?UTF-8?q?n=20du=20min/max=20pour=20les=20param=C3=A8tres=20=C3=A0=20vari?=
 =?UTF-8?q?er=20par=20ex=20:=20conduite=20distributrice,=20calculer=20Pert?=
 =?UTF-8?q?e=20de=20charge,=20varier=20Longueur=20du=20tuyau,=20"calculer"?=
 =?UTF-8?q?=20->=20pas=20de=20graphe?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../param-values/param-values.component.ts    | 31 +++----------------
 1 file changed, 5 insertions(+), 26 deletions(-)

diff --git a/src/app/components/param-values/param-values.component.ts b/src/app/components/param-values/param-values.component.ts
index 0349075f1..e0f63c158 100644
--- a/src/app/components/param-values/param-values.component.ts
+++ b/src/app/components/param-values/param-values.component.ts
@@ -158,28 +158,7 @@ export class ParamValuesComponent implements DoCheck {
         this._valueModes.push({ "value": ParamValueMode.MINMAX, "label": "Min/max" });
         this._valueModes.push({ "value": ParamValueMode.LISTE, "label": "Liste" });
     }
-
-    private getDefaultMin(): number {
-        switch (this._param.domain.domain) {
-            case ParamDomainValue.ANY:
-            case ParamDomainValue.NOT_NULL:
-                return -10;
-
-            default:
-                return this._param.domain.minValue;
-        }
-    }
-
-    private getDefaultMax(): number {
-        switch (this._param.domain.domain) {
-            case ParamDomainValue.INTERVAL:
-                return this._param.domain.maxValue;
-
-            default:
-                return 10;
-        }
-    }
-
+   
     private initMinMaxStep() {
         // valeur pour min (celle déjà définie ou celle déduite du domaine de définition)
         let min: number = this._param.minValue;
@@ -195,7 +174,7 @@ export class ParamValuesComponent implements DoCheck {
             }
         }
         if (!ok)
-            min = this.getDefaultMin();
+            min = this._param.getValue() / 2;
 
         // valeur pour max (celle déjà définie ou celle déduite du domaine de définition)
         let max: number = this._param.maxValue;
@@ -211,13 +190,13 @@ export class ParamValuesComponent implements DoCheck {
             }
         }
         if (!ok)
-            max = this.getDefaultMax();
+            max = this._param.getValue() * 2;
 
         this._minComponent.refValue = new Pair(this._param.domain.minValue, max);
-        this._minComponent.model = this._param.getValue() / 2;
+        this._minComponent.model = min;
 
         this._maxComponent.refValue = new Pair(min, this._param.domain.maxValue);
-        this._maxComponent.model = this._param.getValue() * 2;
+        this._maxComponent.model = max;
 
         this.updateStepComponentRef();
 
-- 
GitLab


From 3e609701d34dcaf20e7c65a611b48badeda3f8ad Mon Sep 17 00:00:00 2001
From: "francois.grand" <francois.grand@irstea.fr>
Date: Fri, 19 Jan 2018 11:17:05 +0100
Subject: [PATCH 08/10] =?UTF-8?q?cr=C3=A9ation=20d'un=20composant=20g?=
 =?UTF-8?q?=C3=A9n=C3=A9rique=20de=20gestion=20de=20liste=20d=C3=A9roulant?=
 =?UTF-8?q?e=20(GenericSelectComponent)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../generic-select.component.html             |  8 +++
 .../generic-select.component.ts               | 58 +++++++++++++++++++
 2 files changed, 66 insertions(+)
 create mode 100644 src/app/components/generic-select/generic-select.component.html
 create mode 100644 src/app/components/generic-select/generic-select.component.ts

diff --git a/src/app/components/generic-select/generic-select.component.html b/src/app/components/generic-select/generic-select.component.html
new file mode 100644
index 000000000..58262b7c2
--- /dev/null
+++ b/src/app/components/generic-select/generic-select.component.html
@@ -0,0 +1,8 @@
+<div class="btn-group" dropdown (click)="onSelect($event)">
+    <button dropdownToggle class="btn btn-primary dropdown-toggle waves-light my-1" type="button" mdbRippleRadius>
+        {{currentLabel}}
+    </button>
+    <div class="dropdown-menu">
+        <a class="dropdown-item" *ngFor="let e of entries" [value]=entryValue(e)>{{entryLabel(e)}}</a>
+    </div>
+</div>
\ No newline at end of file
diff --git a/src/app/components/generic-select/generic-select.component.ts b/src/app/components/generic-select/generic-select.component.ts
new file mode 100644
index 000000000..3c0c0b311
--- /dev/null
+++ b/src/app/components/generic-select/generic-select.component.ts
@@ -0,0 +1,58 @@
+import { Component, Input, Output, EventEmitter } from "@angular/core";
+
+import { SelectField, } from "../../formulaire/select-field";
+import { SelectEntry } from "../../formulaire/select-entry";
+import { FormulaireService } from "../../services/formulaire/formulaire.service";
+
+/*
+  exemple de template :
+  <div class="btn-group col-12 col-sm-9" dropdown (click)="onSelect($event)">
+    <button dropdownToggle class="btn btn-primary dropdown-toggle waves-light my-1" type="button" mdbRippleRadius>
+        {{currentLabel}}
+    </button>
+    <div class="dropdown-menu">
+        <a class="dropdown-item" *ngFor="let e of entries" [value]=e.value>{{e.label}}</a>
+    </div>
+  </div>
+*/
+
+export abstract class GenericSelectComponent {
+    // valeur actuellement sélectionnée
+    // la valeur est le code non affiché repérant une entrée de la liste (cf. [value] dans le templace)
+    private _selectedValue: any;
+
+    /**
+     * selected value event
+     */
+    @Output()
+    private selectChange = new EventEmitter<string>();
+
+    private get currentLabel(): string {
+        if (this._selectedValue != undefined)
+            for (let e of this.entries)
+                if (this.entryValue(e) == this._selectedValue)
+                    return this.entryLabel(e);
+
+        return "<no selection>";
+    }
+
+    private onSelect(event: any) {
+        this._selectedValue = event.target.value;
+        this.selectChange.emit(this._selectedValue);
+    }
+
+    /**
+     * liste des objets sélectionnables
+     */
+    protected abstract get entries(): any[];
+
+    /**
+     * calcule la "valeur" d'une entrée
+     */
+    protected abstract entryValue(entry: any): string;
+
+    /**
+     * calcule l'étiquette d'une entrée (ce qui est affiché dans la liste déroulante)
+     */
+    protected abstract entryLabel(entry: any): string;
+}
-- 
GitLab


From 0d3acc1520a7d27bf2d120622cdb2c159ce4d16f Mon Sep 17 00:00:00 2001
From: "francois.grand" <francois.grand@irstea.fr>
Date: Fri, 19 Jan 2018 12:12:17 +0100
Subject: [PATCH 09/10] =?UTF-8?q?ticket=20#47=20:=20r=C3=A9solution=20de?=
 =?UTF-8?q?=20"D=C3=A9placer=20la=20coche=20histogramme=20aupr=C3=A8s=20du?=
 =?UTF-8?q?=20graphique"=20r=C3=A9solution=20de=20"Mettre=20le=20graphe=20?=
 =?UTF-8?q?en=20scatter=20par=20d=C3=A9faut=20pour=20min,=20max,=20pas=20e?=
 =?UTF-8?q?t=20en=20histogramme=20en=20valeurs=20libres"?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/app/app.module.ts                         |  5 +-
 .../generic-select.component.html             |  2 +-
 .../generic-select.component.ts               | 25 +++++-----
 .../param-values/param-values.component.html  |  5 --
 .../results-graph.component.html              |  6 +++
 .../results-graph/results-graph.component.ts  | 48 +++++++++++++------
 src/app/formulaire/formulaire-definition.ts   |  2 +-
 src/app/formulaire/ngparam.ts                 |  1 -
 8 files changed, 57 insertions(+), 37 deletions(-)

diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index 545d930ee..9c8da9ef4 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -32,7 +32,7 @@ import { GenericCalculatorComponent } from './components/generic-calculator/calc
 import { CalcCanvasComponent } from './components/canvas/canvas.component';
 import { SectionCanvasComponent } from './components/section-canvas/section-canvas.component';
 import { RemousResultsComponent } from './components/remous-results/remous-results.component';
-import { ResultsGraphComponent } from './components/results-graph/results-graph.component';
+import { ResultsGraphComponent, GraphTypeSelectComponent } from './components/results-graph/results-graph.component';
 import { LogComponent } from './components/log/log.component';
 import { CalculatorListComponent } from './components/calculator-list/calculator-list.component';
 import { ApplicationSetupComponent } from './components/app-setup/app-setup.component';
@@ -75,7 +75,8 @@ const appRoutes: Routes = [
     BaseParamInputComponent,
     GenericCalculatorComponent,
     // AlertDialog,
-    CalculatorResultsComponent, FixedVarResultsComponent, SectionResultsComponent, RemousResultsComponent, ResultsGraphComponent,
+    CalculatorResultsComponent, FixedVarResultsComponent, SectionResultsComponent, RemousResultsComponent,
+    ResultsGraphComponent, GraphTypeSelectComponent,
     CalcCanvasComponent, SectionCanvasComponent
   ],
   // entryComponents: [AlertDialog],
diff --git a/src/app/components/generic-select/generic-select.component.html b/src/app/components/generic-select/generic-select.component.html
index 58262b7c2..3506521b3 100644
--- a/src/app/components/generic-select/generic-select.component.html
+++ b/src/app/components/generic-select/generic-select.component.html
@@ -3,6 +3,6 @@
         {{currentLabel}}
     </button>
     <div class="dropdown-menu">
-        <a class="dropdown-item" *ngFor="let e of entries" [value]=entryValue(e)>{{entryLabel(e)}}</a>
+        <a class="dropdown-item" *ngFor="let e of entries" [value]=e>{{entryLabel(e)}}</a>
     </div>
 </div>
\ No newline at end of file
diff --git a/src/app/components/generic-select/generic-select.component.ts b/src/app/components/generic-select/generic-select.component.ts
index 3c0c0b311..7dd5f113a 100644
--- a/src/app/components/generic-select/generic-select.component.ts
+++ b/src/app/components/generic-select/generic-select.component.ts
@@ -6,19 +6,20 @@ import { FormulaireService } from "../../services/formulaire/formulaire.service"
 
 /*
   exemple de template :
-  <div class="btn-group col-12 col-sm-9" dropdown (click)="onSelect($event)">
+
+<div class="btn-group" dropdown (click)="onSelect($event)">
     <button dropdownToggle class="btn btn-primary dropdown-toggle waves-light my-1" type="button" mdbRippleRadius>
         {{currentLabel}}
     </button>
     <div class="dropdown-menu">
-        <a class="dropdown-item" *ngFor="let e of entries" [value]=e.value>{{e.label}}</a>
+        <a class="dropdown-item" *ngFor="let e of entries" [value]=e>{{entryLabel(e)}}</a>
     </div>
-  </div>
+</div>
 */
 
 export abstract class GenericSelectComponent {
     // valeur actuellement sélectionnée
-    // la valeur est le code non affiché repérant une entrée de la liste (cf. [value] dans le templace)
+    // la valeur repère une entrée de la liste (cf. [value] dans le template)
     private _selectedValue: any;
 
     /**
@@ -27,11 +28,14 @@ export abstract class GenericSelectComponent {
     @Output()
     private selectChange = new EventEmitter<string>();
 
+    public set selectedValue(v: any) {
+        this._selectedValue = v;
+    }
+
     private get currentLabel(): string {
-        if (this._selectedValue != undefined)
-            for (let e of this.entries)
-                if (this.entryValue(e) == this._selectedValue)
-                    return this.entryLabel(e);
+        for (let e of this.entries)
+            if (e == this._selectedValue)
+                return this.entryLabel(e);
 
         return "<no selection>";
     }
@@ -46,11 +50,6 @@ export abstract class GenericSelectComponent {
      */
     protected abstract get entries(): any[];
 
-    /**
-     * calcule la "valeur" d'une entrée
-     */
-    protected abstract entryValue(entry: any): string;
-
     /**
      * calcule l'étiquette d'une entrée (ce qui est affiché dans la liste déroulante)
      */
diff --git a/src/app/components/param-values/param-values.component.html b/src/app/components/param-values/param-values.component.html
index 231911877..e3adf9e93 100644
--- a/src/app/components/param-values/param-values.component.html
+++ b/src/app/components/param-values/param-values.component.html
@@ -21,9 +21,4 @@
     <div *ngIf="isList" class="col-12 col-sm-6">
         <value-list title="valeurs séparées par ';'" (onChange)="onListChanged($event)"></value-list>
     </div>
-
-    <div *ngIf="isList" class="col-12 col-sm-3">
-        <input type="checkbox" name="histogram" [(ngModel)]="_param.histogramMode">Histogramme
-        <br/>
-    </div>
 </div>
\ No newline at end of file
diff --git a/src/app/components/results-graph/results-graph.component.html b/src/app/components/results-graph/results-graph.component.html
index b34ec9a0d..316485524 100644
--- a/src/app/components/results-graph/results-graph.component.html
+++ b/src/app/components/results-graph/results-graph.component.html
@@ -3,4 +3,10 @@
         <chart [type]="graph_type" [data]="graph_data" [options]="graph_options">
         </chart>
     </div>
+</div>
+
+<div class="row">
+    <div class="col-4 mx-auto">
+        <graph-type (selectChange)="onGraphTypeSelectChange($event)"></graph-type>
+    </div>
 </div>
\ No newline at end of file
diff --git a/src/app/components/results-graph/results-graph.component.ts b/src/app/components/results-graph/results-graph.component.ts
index bc85c2a18..d52baff5c 100644
--- a/src/app/components/results-graph/results-graph.component.ts
+++ b/src/app/components/results-graph/results-graph.component.ts
@@ -1,6 +1,26 @@
-import { Component, AfterViewInit, EventEmitter, Output } from '@angular/core';
+import { Component, AfterViewInit, EventEmitter, Output, ViewChild } from '@angular/core';
 
 import { FixedVarResults, GraphType } from "../../results/fixed-var-results";
+import { GenericSelectComponent } from '../generic-select/generic-select.component';
+
+@Component({
+    selector: "graph-type",
+    templateUrl: "../generic-select/generic-select.component.html"
+})
+export class GraphTypeSelectComponent extends GenericSelectComponent {
+    private _entries: GraphType[] = [GraphType.Histogram, GraphType.Scatter];
+    private _entriesLabels: string[] = ["Histogramme", "XY"];
+
+    protected get entries(): any[] {
+        return this._entries;
+    }
+
+    protected entryLabel(entry: any): string {
+        // return entry;
+        const i = this._entries.indexOf(entry);
+        return this._entriesLabels[i];
+    }
+}
 
 @Component({
     selector: 'results-graph',
@@ -9,6 +29,11 @@ import { FixedVarResults, GraphType } from "../../results/fixed-var-results";
 export class ResultsGraphComponent { //implements AfterViewInit {
     private _results: FixedVarResults;
 
+    private _currentGraphType: GraphType;
+
+    @ViewChild(GraphTypeSelectComponent)
+    private _graphTypeComponent: GraphTypeSelectComponent;
+
     /*
      * config du graphe
      */
@@ -27,25 +52,19 @@ export class ResultsGraphComponent { //implements AfterViewInit {
             display: true,
             text: ""
         }
-        // scales: {}
     };
 
-    /**
-     * événement émis à la fin de la création de la vue
-     */
-    // @Output()
-    // private onViewInit = new EventEmitter();
-
     public set results(r: FixedVarResults) {
         this._results = r;
-        // this.updateView();
+        this._currentGraphType = r.graphType;
+        this._graphTypeComponent.selectedValue = this._currentGraphType;
     }
 
     // http://www.chartjs.org/docs/latest/charts/line.html#dataset-properties
     //     showLine
 
     public updateView() {
-        switch (this._results.graphType) {
+        switch (this._currentGraphType) {
             case GraphType.Histogram:
                 this.graph_type = "bar";
                 this.generateBarGraph();
@@ -63,9 +82,10 @@ export class ResultsGraphComponent { //implements AfterViewInit {
         }
     }
 
-    // public ngAfterViewInit() {
-    //     this.onViewInit.emit();
-    // }
+    private onGraphTypeSelectChange(event) {
+        this._currentGraphType = event;
+        this.updateView();
+    }
 
     /**
      * génère les données d'un graphe de type "line"
@@ -157,4 +177,4 @@ export class ResultsGraphComponent { //implements AfterViewInit {
             ]
         };
     }
-}
\ No newline at end of file
+}
diff --git a/src/app/formulaire/formulaire-definition.ts b/src/app/formulaire/formulaire-definition.ts
index a83a91287..8bd2ed0b6 100644
--- a/src/app/formulaire/formulaire-definition.ts
+++ b/src/app/formulaire/formulaire-definition.ts
@@ -1139,7 +1139,7 @@ export class FormulaireDefinition extends Observable {
                     break;
 
                 case ParamValueMode.LISTE:
-                    this._fixVarResults.graphType = varParam.histogramMode ? GraphType.Histogram : GraphType.Scatter;
+                    this._fixVarResults.graphType = GraphType.Histogram;
 
                     for (let val of varParam.valueList) {
                         prms[varParam.symbol].v = val;
diff --git a/src/app/formulaire/ngparam.ts b/src/app/formulaire/ngparam.ts
index 16dd165eb..9d94db8e4 100644
--- a/src/app/formulaire/ngparam.ts
+++ b/src/app/formulaire/ngparam.ts
@@ -52,7 +52,6 @@ export class NgParameter extends InputField {
     public stepValue: number; // pas de progression dans le cas ParamRadioConfig.VAR
     public valueList: number[];
     public valueMode: ParamValueMode = ParamValueMode.MINMAX;
-    public histogramMode: boolean = false; // A VIRER et deplacer dans FixVarResults
 
     constructor(private _paramDef: ParamDefinition, formId: number) {
         super(_paramDef.computeNodeType, _paramDef.symbol, formId);
-- 
GitLab


From 67ce4489c12f2b6bf9cd2e83115571b77837fb98 Mon Sep 17 00:00:00 2001
From: "francois.grand" <francois.grand@irstea.fr>
Date: Fri, 19 Jan 2018 12:20:38 +0100
Subject: [PATCH 10/10] =?UTF-8?q?ticket=20#47=20:=20r=C3=A9solution=20de?=
 =?UTF-8?q?=20"Relier=20les=20points=20en=20mode=20scatter"?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../components/results-graph/results-graph.component.ts   | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/src/app/components/results-graph/results-graph.component.ts b/src/app/components/results-graph/results-graph.component.ts
index d52baff5c..83b55ff98 100644
--- a/src/app/components/results-graph/results-graph.component.ts
+++ b/src/app/components/results-graph/results-graph.component.ts
@@ -60,9 +60,6 @@ export class ResultsGraphComponent { //implements AfterViewInit {
         this._graphTypeComponent.selectedValue = this._currentGraphType;
     }
 
-    // http://www.chartjs.org/docs/latest/charts/line.html#dataset-properties
-    //     showLine
-
     public updateView() {
         switch (this._currentGraphType) {
             case GraphType.Histogram:
@@ -171,8 +168,9 @@ export class ResultsGraphComponent { //implements AfterViewInit {
                 {
                     label: "",
                     data: dat,
-                    // borderColor: '#000000',
-                    // backgroundColor: '#000000'
+                    borderColor: "#808080", // couleur de la ligne
+                    backgroundColor: "rgba(0,0,0,0)",  // couleur de remplissage sous la courbe : transparent
+                    showLine: "true"
                 }
             ]
         };
-- 
GitLab