From 7c7920baa01f7cf7a55cc68c7b429df2c807f9d1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr>
Date: Thu, 29 Sep 2022 15:11:02 +0200
Subject: [PATCH 1/5] feat: parameterised sections: add check button to apply
 1:1 aspect ratio to graph

refs #497
---
 .../section-canvas.component.html             |   9 +-
 .../section-canvas.component.ts               | 250 ++++++++++++------
 src/locale/messages.en.json                   |   1 +
 src/locale/messages.fr.json                   |   1 +
 4 files changed, 185 insertions(+), 76 deletions(-)

diff --git a/src/app/components/section-canvas/section-canvas.component.html b/src/app/components/section-canvas/section-canvas.component.html
index da242b966..fc687f76c 100644
--- a/src/app/components/section-canvas/section-canvas.component.html
+++ b/src/app/components/section-canvas/section-canvas.component.html
@@ -1,2 +1,7 @@
-<canvas #canvas [attr.width]="width" [attr.height]="height">
-</canvas>
+<div fxLayout="column" fxLayoutAlign="center center">
+    <canvas #canvas [attr.width]="width" [attr.height]="height">
+    </canvas>
+    <mat-checkbox [ngModel]="useRealAspectRatio" (ngModelChange)="setUseRealAspectRatio($event)">
+        {{ uitextUseRealRatio }}
+    </mat-checkbox>
+</div>
\ No newline at end of file
diff --git a/src/app/components/section-canvas/section-canvas.component.ts b/src/app/components/section-canvas/section-canvas.component.ts
index 41364eac3..be18032fa 100644
--- a/src/app/components/section-canvas/section-canvas.component.ts
+++ b/src/app/components/section-canvas/section-canvas.component.ts
@@ -1,4 +1,5 @@
 import { Component, ViewChild, Input, OnChanges, AfterViewInit, ElementRef } from "@angular/core";
+import { I18nService } from "app/services/internationalisation.service";
 
 import {
     acSection, cSnTrapez, ParamsSectionTrapez, cSnRectang, ParamsSectionRectang, cSnCirc,
@@ -40,19 +41,44 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
 
     private _result: Result;
 
+    /**
+     * paramètre de taille du canvas en entrée (pixels)
+     */
     private _size: number;
 
+    /**
+     * taille horizontale résultante, suivant le flag de respect de l'échelle (pixels)
+     */
+    private _sizeX: number;
+
+    /**
+     * taille verticale résultante, suivant le flag de respect de l'échelle (pixels)
+     */
+    private _sizeY: number;
+
+    /**
+     * taille horizontale de la section (m)
+     */
+    private _sectionWidth: number;
+
+    /**
+     * taille verticale de la section (m)
+     */
+    private _sectionHeight: number;
+
     // tirants
     private _levels: Object[] = [];
 
+    constructor(private intlService: I18nService) {
+        super();
+    }
+
     public get width(): number {
-        // return this._calcCanvas.nativeElement.width;
-        return this._size;
+        return this._sizeX;
     }
 
     public get height(): number {
-        // return this._calcCanvas.nativeElement.height;
-        return this._size;
+        return this._sizeY;
     }
 
     private _context2d: CanvasRenderingContext2D;
@@ -63,6 +89,7 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
     @Input()
     public set section(s: acSection) {
         this._section = s;
+        this.computeSectionWidth();
     }
 
     @Input()
@@ -75,6 +102,9 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
         this._size = s;
     }
 
+    // respect du rapport abscisses/ordonnées
+    public useRealAspectRatio: boolean = false;
+
     // redessine le canvas chaque fois qu'une entrée change
     public ngOnChanges() {
         setTimeout(() => {
@@ -92,7 +122,30 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
         this.clear();
     }
 
-    public addLevel(val: number, label: string, rgb: {}) {
+    /**
+     * calcul des tailles horizontale et verticale du canvas (pixels)
+     */
+    private updateCanvasSize() {
+        if (this.useRealAspectRatio) {
+            if (this._sectionWidth > this._sectionHeight) {
+                this._sizeX = this._size;
+                this._sizeY = this._size * this._sectionHeight / this._sectionWidth;
+            }
+            else {
+                this._sizeX = this._size * this._sectionHeight / this._sectionWidth;
+                this._sizeY = this._size;
+            }
+        } else {
+            this._sizeX = this._sizeY = this._size;
+        }
+    }
+
+    public setUseRealAspectRatio(b: boolean) {
+        this.useRealAspectRatio = b;
+        this.draw();
+    }
+
+    private addLevel(val: number, label: string, rgb: {}) {
         this._levels.push({ val, label, rgb });
     }
 
@@ -111,6 +164,26 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
         return false;
     }
 
+    /**
+     * calcul des tailles horizontale et verticale de la section (m)
+     */
+    private computeSectionWidth() {
+        if (this._section instanceof cSnTrapez) {
+            this.computeSectionWidthTrapez();
+        }
+        else if (this._section instanceof cSnRectang) {
+            this.computeSectionWidthRect();
+        }
+        else if (this._section instanceof cSnCirc) {
+            this.computeSectionWidthCirc();
+        }
+        else if (this._section instanceof cSnPuiss) {
+            this.computeSectionWidthPara();
+        }
+        else
+            throw new Error("SectionCanvasComponent.computeSectionWidth() : type de section non pris en charge");
+    }
+
     public draw() {
         // console.log(">> redrawing at size", this._size);
         if (this._context2d && this._section) {
@@ -136,10 +209,13 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
             const valY = this._result.sourceNub.getParameter("Y").singleValue;
             this.addLevel(valY, "Y = " + this.formattedValue(valY), SectionCanvasComponent.labelColors["Y"]);
 
-            this.sortLevels();
-            this.drawFrame();
-            const maxWidth = this.drawSection();
-            this.drawLevels(maxWidth);
+            this.computeSectionHeight();
+            this.updateCanvasSize();
+            setTimeout(() => { // à cause du changement de taille du canvas dans updateCanvasSize()
+                this.drawFrame();
+                this.drawSection();
+                this.drawLevels();
+            }, 10);
         }
     }
 
@@ -157,24 +233,35 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
         this.drawSectionLine(xmax, yb, xmax, maxHeight);
     }
 
-    private drawSectionTrapez(): number {
+    private computeSectionHeight() {
+        this.sortLevels();
+
+        // hauteur totale de la section
+        this._sectionHeight = this.getMaxLevel() * 1.1;
+    }
+
+    private computeSectionWidthTrapez() {
         const sect: cSnTrapez = <cSnTrapez>this._section;
         const prms: ParamsSectionTrapez = <ParamsSectionTrapez>sect.prms;
 
-        // cote de berge
-        const yb: number = prms.YB.v;
-
         // largeur de la partie pentue
         const lp: number = prms.Fruit.v * prms.YB.v;
 
         // largeur totale de la section
-        const maxWidth: number = lp * 2 + prms.LargeurFond.v;
+        this._sectionWidth = lp * 2 + prms.LargeurFond.v;
+    }
 
-        // hauteur totale de la section
-        let maxHeight: number = this.getMaxLevel();
-        maxHeight *= 1.1;
+    private drawSectionTrapez() {
+        const sect: cSnTrapez = <cSnTrapez>this._section;
+        const prms: ParamsSectionTrapez = <ParamsSectionTrapez>sect.prms;
 
-        this.computeScale(maxWidth, maxHeight);
+        // cote de berge
+        const yb: number = prms.YB.v;
+
+        // largeur de la partie pentue
+        const lp: number = prms.Fruit.v * prms.YB.v;
+
+        this.computeScale();
 
         // dessin de la section
 
@@ -182,13 +269,19 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
         this.setLineWidth(5);
         this.drawSectionLine(0, yb, lp, 0);
         this.drawSectionLine(lp, 0, lp + prms.LargeurFond.v, 0);
-        this.drawSectionLine(lp + prms.LargeurFond.v, 0, maxWidth, yb);
+        this.drawSectionLine(lp + prms.LargeurFond.v, 0, this._sectionWidth, yb);
 
         // pointillés du haut
 
-        this.drawTopDashLines(0, maxWidth, yb, maxHeight);
+        this.drawTopDashLines(0, this._sectionWidth, yb, this._sectionHeight);
+    }
+
+    private computeSectionWidthRect() {
+        const sect: cSnRectang = <cSnRectang>this._section;
+        const prms: ParamsSectionRectang = <ParamsSectionRectang>sect.prms;
 
-        return maxWidth;
+        // largeur totale de la section
+        this._sectionWidth = prms.LargeurBerge.v;
     }
 
     private drawSectionRect() {
@@ -198,14 +291,7 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
         // cote de berge
         const yb: number = prms.YB.v;
 
-        // largeur totale de la section
-        const maxWidth: number = prms.LargeurBerge.v;
-
-        // hauteur totale de la section
-        let maxHeight: number = this.getMaxLevel();
-        maxHeight *= 1.1;
-
-        this.computeScale(maxWidth, maxHeight);
+        this.computeScale();
 
         // dessin de la section
 
@@ -213,13 +299,32 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
         this.setLineWidth(5);
         this.drawSectionLine(0, yb, 0, 0);
         this.drawSectionLine(0, 0, prms.LargeurBerge.v, 0);
-        this.drawSectionLine(prms.LargeurBerge.v, 0, maxWidth, yb);
+        this.drawSectionLine(prms.LargeurBerge.v, 0, this._sectionWidth, yb);
 
         // pointillés du haut
 
-        this.drawTopDashLines(0, maxWidth, yb, maxHeight);
+        this.drawTopDashLines(0, this._sectionWidth, yb, this._sectionHeight);
+    }
+
+    private computeSectionWidthCirc() {
+        const sect: cSnCirc = <cSnCirc>this._section;
+        const prms: ParamsSectionCirc = <ParamsSectionCirc>sect.prms;
+
+        // cote de berge
+        const yb: number = prms.YB.v;
+
+        // diamètre, rayon
+        const D: number = prms.D.v;
+        const r: number = D / 2;
+
+        // largeur au miroir
+        const B: Result = sect.CalcSection("B", yb);
+        if (!B.ok) {
+            throw B;
+        }
 
-        return maxWidth;
+        // largeur totale de la section
+        this._sectionWidth = yb < r ? B.vCalc : D;
     }
 
     private drawSectionCirc() {
@@ -240,21 +345,14 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
                 throw B;
             }
 
-            // largeur totale de la section
-            const maxWidth: number = yb < r ? B.vCalc : D;
-
-            // hauteur totale de la section
-            let maxHeight: number = this.getMaxLevel();
-            maxHeight *= 1.1;
-
-            this.computeScale(maxWidth, maxHeight);
+            this.computeScale();
 
             // dessin de la section
 
             this.setStrokeColor(0, 0, 0);
             this.setLineWidth(5);
 
-            const wx: number = maxWidth / 2;
+            const wx: number = this._sectionWidth / 2;
             const alpha: Result = sect.CalcSection("Alpha", yb);
             if (!alpha.ok) {
                 throw alpha;
@@ -267,15 +365,24 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
             // pointillés du haut
 
             const w: number = yb > r ? (D - B.vCalc) / 2 : 0;
-            this.drawTopDashLines(w, maxWidth - w, yb, maxHeight);
-
-            return maxWidth;
+            this.drawTopDashLines(w, this._sectionWidth - w, yb, this._sectionHeight);
         } catch (e) {
             const res: Result = e as Result;
             this.drawText("error : " + res.log.toString(), 0, 0);
         }
     }
 
+    private computeSectionWidthPara() {
+        const sect: cSnPuiss = <cSnPuiss>this._section;
+        const prms: ParamsSectionPuiss = <ParamsSectionPuiss>sect.prms;
+
+        // largeur au miroir
+        const B: number = prms.LargeurBerge.v;
+
+        // largeur totale de la section
+        this._sectionWidth = B;
+    }
+
     private drawSectionPara() {
         const sect: cSnPuiss = <cSnPuiss>this._section;
         const prms: ParamsSectionPuiss = <ParamsSectionPuiss>sect.prms;
@@ -286,14 +393,7 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
         // largeur au miroir
         const B: number = prms.LargeurBerge.v;
 
-        // largeur totale de la section
-        const maxWidth: number = B;
-
-        // hauteur totale de la section
-        let maxHeight: number = this.getMaxLevel();
-        maxHeight *= 1.1;
-
-        this.computeScale(maxWidth, maxHeight);
+        this.computeScale();
 
         // contour de la section
 
@@ -312,9 +412,7 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
         this._context2d.stroke();
 
         // pointillés du haut
-        this.drawTopDashLines(0, maxWidth, yb, maxHeight);
-
-        return maxWidth;
+        this.drawTopDashLines(0, this._sectionWidth, yb, this._sectionHeight);
     }
 
     private drawSectionEllipse(x: number, y: number, rX: number, rY: number, rot: number, start: number, end: number) {
@@ -333,25 +431,26 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
      * dessin de la section
      * @returns largeur de la section (en m)
      */
-    private drawSection(): number {
+    private drawSection() {
         if (this._section instanceof cSnTrapez) {
-            return this.drawSectionTrapez();
+            this.drawSectionTrapez();
         }
-        if (this._section instanceof cSnRectang) {
-            return this.drawSectionRect();
+        else if (this._section instanceof cSnRectang) {
+            this.drawSectionRect();
         }
-        if (this._section instanceof cSnCirc) {
-            return this.drawSectionCirc();
+        else if (this._section instanceof cSnCirc) {
+            this.drawSectionCirc();
         }
-        if (this._section instanceof cSnPuiss) {
-            return this.drawSectionPara();
+        else if (this._section instanceof cSnPuiss) {
+            this.drawSectionPara();
         }
-        throw new Error("SectionCanvasComponent.drawSection() : type de section non pris en charge");
+        else
+            throw new Error("SectionCanvasComponent.drawSection() : type de section non pris en charge");
     }
 
-    private computeScale(maxWidth: number, maxHeight: number) {
-        this._scaleX = (this._size - 2 * this._textMargin) / maxWidth;
-        this._scaleY = (this._size - this._bottomMargin) / maxHeight;
+    private computeScale() {
+        this._scaleX = (this._sizeX - 2 * this._textMargin) / this._sectionWidth;
+        this._scaleY = (this._sizeY - this._bottomMargin) / this._sectionHeight;
     }
 
     /**
@@ -365,7 +464,7 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
      * convertit une ordonnée en m en pixels
      */
     private Ym2pix(y: number) {
-        return this._size - this._bottomMargin - y * this._scaleY;
+        return this._sizeY - this._bottomMargin - y * this._scaleY;
     }
 
     private sortLevels() {
@@ -380,7 +479,7 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
         });
     }
 
-    private drawLevels(maxWidth: number) {
+    private drawLevels() {
         let left = true;
 
         this.resetLineDash();
@@ -390,13 +489,13 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
             const y = l["val"];
             const col = l["rgb"];
             this.setStrokeColor(col["r"], col["g"], col["b"]);
-            this.drawSectionLine(0, y, maxWidth, y);
+            this.drawSectionLine(0, y, this._sectionWidth, y);
 
             this.setFillColor(col["r"], col["g"], col["b"]);
             if (left) {
                 this.drawText(l["label"], -0.1, y, "right");
             } else {
-                this.drawText(l["label"], maxWidth + 0.1, y, "left");
+                this.drawText(l["label"], this._sectionWidth + 0.1, y, "left");
             }
             left = !left;
         }
@@ -404,15 +503,14 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
 
     // contour du canvas
     private drawFrame() {
-        this.clear();
         this.resetLineDash();
         this.setStrokeColor(128, 128, 128);
-        this.drawRect(0, 0, this.width, this.height);
+        this.drawRect(0, 0, this._sizeX, this._sizeY);
     }
 
     public clear() {
         if (this._context2d) {
-            this._context2d.clearRect(0, 0, this.width, this.height);
+            this._context2d.clearRect(0, 0, this._sizeX, this._sizeY);
         }
     }
 
@@ -475,4 +573,8 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
         this._context2d.ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle);
         this._context2d.stroke();
     }
+
+    public get uitextUseRealRatio(): string {
+        return this.intlService.localizeText("INFO_SECTIONPARAMETREE_REAL_RATIO");
+    }
 }
diff --git a/src/locale/messages.en.json b/src/locale/messages.en.json
index 56a2f105b..80c1a982c 100755
--- a/src/locale/messages.en.json
+++ b/src/locale/messages.en.json
@@ -584,6 +584,7 @@
     "INFO_SECTIONPARAMETREE_DESCRIPTION": "open-channel canal rectangular circular trapezoidal depth head normal critical conjugate corresponding subcritical supercritical Froude",
     "INFO_SECTIONPARAMETREE_TITRE_COURT": "Param. section",
     "INFO_SECTIONPARAMETREE_TITRE": "Parametric section",
+    "INFO_SECTIONPARAMETREE_REAL_RATIO": "Apply 1:1 scale",
     "INFO_SELECT_MULTIPLE_AND_OTHER": "other",
     "INFO_SELECT_MULTIPLE_AND_OTHERS": "others",
     "INFO_SETUP_ENABLE_HOTKEYS": "Enable keyboard shortcuts",
diff --git a/src/locale/messages.fr.json b/src/locale/messages.fr.json
index 225b0751e..77a92907f 100755
--- a/src/locale/messages.fr.json
+++ b/src/locale/messages.fr.json
@@ -585,6 +585,7 @@
     "INFO_SECTIONPARAMETREE_DESCRIPTION": "hydraulique à surface libre canal chenal bief rectangulaire circulaire puissance trapézoïdale périmètre charge mouillée rugosité hauteur charge critique normal conjuguée correspondante fluvial torrentiel Froude",
     "INFO_SECTIONPARAMETREE_TITRE_COURT": "Sec. param.",
     "INFO_SECTIONPARAMETREE_TITRE": "Section paramétrée",
+    "INFO_SECTIONPARAMETREE_REAL_RATIO": "Respecter l'échelle",
     "INFO_SELECT_MULTIPLE_AND_OTHER": "autre",
     "INFO_SELECT_MULTIPLE_AND_OTHERS": "autres",
     "INFO_SETUP_ENABLE_HOTKEYS": "Activer les raccourcis clavier",
-- 
GitLab


From 8b5cfc6bd0066c1c0c22fbdb5ddc1ede92abdc4b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr>
Date: Wed, 5 Oct 2022 11:52:34 +0200
Subject: [PATCH 2/5] fix: parametric section graph: keep canvas the same size,
 fix text at the wrong place with narrow embankment

refs #497
---
 .../section-canvas.component.ts               | 98 ++++++++++++-------
 1 file changed, 61 insertions(+), 37 deletions(-)

diff --git a/src/app/components/section-canvas/section-canvas.component.ts b/src/app/components/section-canvas/section-canvas.component.ts
index be18032fa..965f6b7c7 100644
--- a/src/app/components/section-canvas/section-canvas.component.ts
+++ b/src/app/components/section-canvas/section-canvas.component.ts
@@ -27,11 +27,19 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
         "Y": { r: 50, g: 50, b: 50 }
     };
 
+    /*
+     * l'origine des coordonnées en m est par ex pour la section rectangulaire
+     * le coin en bas (radier) à gauche de la section
+     */
+
     /** marges gauche/droite pour le texte (pixels) */
-    private _textMargin = 90;
+    private readonly _textMargin = 90;
 
     /** marge basse (pixels) */
-    private _bottomMargin = 5;
+    private readonly _bottomMargin = 5;
+
+    /** largeur des repères des niveaux sur le bord de la section (pixels) */
+    private readonly _levelMark = 5;
 
     /** facteurs d'échelle (coordonnées en m <-> coordonnées en pixels) */
     private _scaleX: number;
@@ -47,14 +55,14 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
     private _size: number;
 
     /**
-     * taille horizontale résultante, suivant le flag de respect de l'échelle (pixels)
+     * taille horizontale de rendu de la section (sans le texte) à l'intérieur du canvas suivant le flag de respect de l'échelle (pixels)
      */
-    private _sizeX: number;
+    private _renderSectionX: number;
 
     /**
-     * taille verticale résultante, suivant le flag de respect de l'échelle (pixels)
+     * taille verticale de rendu de la section à l'intérieur du canvas suivant le flag de respect de l'échelle (pixels)
      */
-    private _sizeY: number;
+    private _renderSectionY: number;
 
     /**
      * taille horizontale de la section (m)
@@ -62,7 +70,7 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
     private _sectionWidth: number;
 
     /**
-     * taille verticale de la section (m)
+     * taille verticale de la section en comptant les tirants (m)
      */
     private _sectionHeight: number;
 
@@ -74,11 +82,11 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
     }
 
     public get width(): number {
-        return this._sizeX;
+        return this._size;
     }
 
     public get height(): number {
-        return this._sizeY;
+        return this._size;
     }
 
     private _context2d: CanvasRenderingContext2D;
@@ -114,7 +122,6 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
 
     public ngAfterViewInit() { // wait for the view to init before using the element
         this._context2d = this._calcCanvas.nativeElement.getContext("2d");
-        this.draw();
     }
 
     public reset() {
@@ -123,20 +130,21 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
     }
 
     /**
-     * calcul des tailles horizontale et verticale du canvas (pixels)
+     * calcul des tailles horizontale et verticale de la zone de rendu de la section à l'intérieur du canvas (pixels)
      */
-    private updateCanvasSize() {
+    private computeRenderSize() {
         if (this.useRealAspectRatio) {
             if (this._sectionWidth > this._sectionHeight) {
-                this._sizeX = this._size;
-                this._sizeY = this._size * this._sectionHeight / this._sectionWidth;
+                this._renderSectionX = this._size - 2 * (this._textMargin + this._levelMark)
+                this._renderSectionY = (this._size - this._bottomMargin) * this._sectionHeight / this._sectionWidth;
             }
             else {
-                this._sizeX = this._size * this._sectionHeight / this._sectionWidth;
-                this._sizeY = this._size;
+                this._renderSectionX = this._size * this._sectionWidth / this._sectionHeight;
+                this._renderSectionY = this._size - this._bottomMargin;;
             }
         } else {
-            this._sizeX = this._sizeY = this._size;
+            this._renderSectionX = this._size - 2 * (this._textMargin + this._levelMark)
+            this._renderSectionY = this._size - this._bottomMargin;
         }
     }
 
@@ -194,7 +202,7 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
             if (re !== undefined) {
                 for (const k in re.values) {
                     if (k !== re.vCalcSymbol) {
-                        const lbl = k.toUpperCase();
+                        //const lbl = k.toUpperCase();
                         const er = re.getValue(k);
                         // this._resultElement.addExtraResult(lbl, er);
 
@@ -210,7 +218,8 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
             this.addLevel(valY, "Y = " + this.formattedValue(valY), SectionCanvasComponent.labelColors["Y"]);
 
             this.computeSectionHeight();
-            this.updateCanvasSize();
+            this.computeRenderSize();
+            this.computeScale();
             setTimeout(() => { // à cause du changement de taille du canvas dans updateCanvasSize()
                 this.drawFrame();
                 this.drawSection();
@@ -261,8 +270,6 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
         // largeur de la partie pentue
         const lp: number = prms.Fruit.v * prms.YB.v;
 
-        this.computeScale();
-
         // dessin de la section
 
         this.setStrokeColor(0, 0, 0);
@@ -291,15 +298,14 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
         // cote de berge
         const yb: number = prms.YB.v;
 
-        this.computeScale();
 
         // dessin de la section
 
         this.setStrokeColor(0, 0, 0);
         this.setLineWidth(5);
         this.drawSectionLine(0, yb, 0, 0);
-        this.drawSectionLine(0, 0, prms.LargeurBerge.v, 0);
-        this.drawSectionLine(prms.LargeurBerge.v, 0, this._sectionWidth, yb);
+        this.drawSectionLine(0, 0, this._sectionWidth, 0);
+        this.drawSectionLine(this._sectionWidth, 0, this._sectionWidth, yb);
 
         // pointillés du haut
 
@@ -345,8 +351,6 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
                 throw B;
             }
 
-            this.computeScale();
-
             // dessin de la section
 
             this.setStrokeColor(0, 0, 0);
@@ -393,8 +397,6 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
         // largeur au miroir
         const B: number = prms.LargeurBerge.v;
 
-        this.computeScale();
-
         // contour de la section
 
         this.setStrokeColor(0, 0, 0);
@@ -419,8 +421,17 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
         this.drawEllipse(this.Xm2pix(x), this.Ym2pix(y), rX * this._scaleX, rY * this._scaleY, rot, start, end);
     }
 
+    /**
+     * dessine un texte
+     * @param s texte à dessiner
+     * @param x position horizontale (m)
+     * @param y position verticale (m)
+     * @param align alignement "left" ou "right" cf. https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/textAlign
+     */
     private drawText(s: string, x: number, y: number, align?: string) {
-        this.fillText(s, this.Xm2pix(x), this.Ym2pix(y), align);
+        // décalage du texte par rapport au bord gauche/droit de la section
+        const shiftX = align === undefined ? 0 : (align === "left" ? this._levelMark : -this._levelMark);
+        this.fillText(s, this.Xm2pix(x) + shiftX, this.Ym2pix(y), align);
     }
 
     private drawSectionLine(x1: number, y1: number, x2: number, y2: number) {
@@ -449,22 +460,28 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
     }
 
     private computeScale() {
-        this._scaleX = (this._sizeX - 2 * this._textMargin) / this._sectionWidth;
-        this._scaleY = (this._sizeY - this._bottomMargin) / this._sectionHeight;
+        this._scaleX = this._renderSectionX / this._sectionWidth;
+        this._scaleY = this._renderSectionY / this._sectionHeight;
     }
 
     /**
      * convertit une abscisse en m en pixels
      */
     private Xm2pix(x: number) {
-        return this._textMargin + x * this._scaleX;
+        // origine X de la section dans le canvas
+        const origX = (this._size - this._renderSectionX) / 2;
+
+        return origX + x * this._scaleX;
     }
 
     /**
      * convertit une ordonnée en m en pixels
      */
     private Ym2pix(y: number) {
-        return this._sizeY - this._bottomMargin - y * this._scaleY;
+        // origine Y de la section dans le canvas
+        const origY = (this._size - this._renderSectionY) / 2;
+
+        return this._size - this._bottomMargin - origY - y * this._scaleY;
     }
 
     private sortLevels() {
@@ -493,9 +510,9 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
 
             this.setFillColor(col["r"], col["g"], col["b"]);
             if (left) {
-                this.drawText(l["label"], -0.1, y, "right");
+                this.drawText(l["label"], 0, y, "right");
             } else {
-                this.drawText(l["label"], this._sectionWidth + 0.1, y, "left");
+                this.drawText(l["label"], this._sectionWidth, y, "left");
             }
             left = !left;
         }
@@ -505,12 +522,12 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
     private drawFrame() {
         this.resetLineDash();
         this.setStrokeColor(128, 128, 128);
-        this.drawRect(0, 0, this._sizeX, this._sizeY);
+        this.drawRect(0, 0, this._size, this._size);
     }
 
     public clear() {
         if (this._context2d) {
-            this._context2d.clearRect(0, 0, this._sizeX, this._sizeY);
+            this._context2d.clearRect(0, 0, this._size, this._size);
         }
     }
 
@@ -528,6 +545,13 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
         this._context2d.font = f;
     }
 
+    /**
+     * dessine un texte sur le canvas
+     * @param s texte à dessiner
+     * @param x position horizontale (pixels)
+     * @param y position verticale (pixels)
+     * @param align alignement "left" ou "right" cf. https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/textAlign
+     */
     public fillText(s: string, x: number, y: number, align?: any) {
         if (align) {
             this._context2d.textAlign = align;
-- 
GitLab


From 698e52e0aa80aa5b238db8de3dd98b3409b0f87d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr>
Date: Thu, 6 Oct 2022 09:29:31 +0200
Subject: [PATCH 3/5] fix: parametric sections graph: circular section wrongly
 displayed in 1:1 mode

refs #497
---
 .../section-canvas.component.ts               | 261 ++++++++++--------
 1 file changed, 149 insertions(+), 112 deletions(-)

diff --git a/src/app/components/section-canvas/section-canvas.component.ts b/src/app/components/section-canvas/section-canvas.component.ts
index 965f6b7c7..0c7a71635 100644
--- a/src/app/components/section-canvas/section-canvas.component.ts
+++ b/src/app/components/section-canvas/section-canvas.component.ts
@@ -28,16 +28,24 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
     };
 
     /*
-     * l'origine des coordonnées en m est par ex pour la section rectangulaire
-     * le coin en bas (radier) à gauche de la section
+     * notes :
+     * - l'origine des coordonnées en m est par ex pour la section rectangulaire le coin en bas (radier) à gauche de la section
+     * - canal : partie physique, sans les niveaux d'eau
+     * - section : canal + niveaux d'eau
+     * - rendu : section + texte + pointillés en haut
+     * - W : dimension horizontale, H : dimension verticale
+     * _ _m : valeur en mètres, _pix : valeur en pixels
      */
 
-    /** marges gauche/droite pour le texte (pixels) */
-    private readonly _textMargin = 90;
+    /** largeur gauche/droite du texte (pixels) */
+    private readonly _textWidth = 110;
 
     /** marge basse (pixels) */
     private readonly _bottomMargin = 5;
 
+    /** marge haute pour les pointillés (pixels) */
+    private readonly _topDashMargin = 30;
+
     /** largeur des repères des niveaux sur le bord de la section (pixels) */
     private readonly _levelMark = 5;
 
@@ -45,6 +53,10 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
     private _scaleX: number;
     private _scaleY: number;
 
+    /** origine (pixels) */
+    private _origX: number;
+    private _origY: number;
+
     private _section: acSection;
 
     private _result: Result;
@@ -55,24 +67,24 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
     private _size: number;
 
     /**
-     * taille horizontale de rendu de la section (sans le texte) à l'intérieur du canvas suivant le flag de respect de l'échelle (pixels)
+     * taille horizontale de la section (m)
      */
-    private _renderSectionX: number;
+    private _Wsect_m: number;
 
     /**
-     * taille verticale de rendu de la section à l'intérieur du canvas suivant le flag de respect de l'échelle (pixels)
+     * taille verticale de la section (m)
      */
-    private _renderSectionY: number;
+    private _Hsect_m: number;
 
     /**
-     * taille horizontale de la section (m)
+     * taille horizontale de la section (pixels)
      */
-    private _sectionWidth: number;
+    private _Wsect_pix: number;
 
     /**
-     * taille verticale de la section en comptant les tirants (m)
+     * taille verticale de la section (pixels)
      */
-    private _sectionHeight: number;
+    private _Hsect_pix: number;
 
     // tirants
     private _levels: Object[] = [];
@@ -97,7 +109,6 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
     @Input()
     public set section(s: acSection) {
         this._section = s;
-        this.computeSectionWidth();
     }
 
     @Input()
@@ -111,10 +122,13 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
     }
 
     // respect du rapport abscisses/ordonnées
-    public useRealAspectRatio: boolean = false;
+    private _useRealAspectRatio: boolean = false;
 
     // redessine le canvas chaque fois qu'une entrée change
     public ngOnChanges() {
+        this.computeSectionWidth();
+        this.computeSectionHeight();
+        this.computeTransform();
         setTimeout(() => {
             this.draw();
         }, 10);
@@ -124,39 +138,121 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
         this._context2d = this._calcCanvas.nativeElement.getContext("2d");
     }
 
-    public reset() {
-        this._levels = [];
-        this.clear();
-    }
-
     /**
-     * calcul des tailles horizontale et verticale de la zone de rendu de la section à l'intérieur du canvas (pixels)
+     * calcul des tailles horizontale et verticale de la zone de rendu (pixels)
+     * @returns true si le rendu touche le haut et le bas du canvas
      */
-    private computeRenderSize() {
-        if (this.useRealAspectRatio) {
-            if (this._sectionWidth > this._sectionHeight) {
-                this._renderSectionX = this._size - 2 * (this._textMargin + this._levelMark)
-                this._renderSectionY = (this._size - this._bottomMargin) * this._sectionHeight / this._sectionWidth;
+    private computeRenderSize(): boolean {
+        let res: boolean;
+        if (this._useRealAspectRatio) {
+            // largeur en pixels pour la représentation de la section
+            const a = this.width - 2 * (this._textWidth + this._levelMark);
+
+            // calcul des rapports largeur/hauteur pour le canvas et la section
+            const rlim = a / this.height;
+            const rsect = this._Wsect_m / this._Hsect_m;
+
+            if (rsect <= rlim) {
+                this._Hsect_pix = this.height - this._bottomMargin - this._topDashMargin;
+                this._Wsect_pix = this._Hsect_pix * rsect;
+                res = true;
             }
             else {
-                this._renderSectionX = this._size * this._sectionWidth / this._sectionHeight;
-                this._renderSectionY = this._size - this._bottomMargin;;
+                this._Wsect_pix = a;
+                this._Hsect_pix = this._Wsect_pix / rsect;
+                res = false;
             }
+
         } else {
-            this._renderSectionX = this._size - 2 * (this._textMargin + this._levelMark)
-            this._renderSectionY = this._size - this._bottomMargin;
+            this._Wsect_pix = this.width - 2 * (this._textWidth + this._levelMark)
+            this._Hsect_pix = this.height - this._bottomMargin - this._topDashMargin;
+            res = true;
         }
+
+        return res;
+    }
+
+    /**
+     * calcul du coef pour passer de m -> pixels
+     * et de l'origine du rendu
+     */
+    private computeTransform() {
+        const b = this.computeRenderSize();
+
+        // échelle m -> pix
+        this._scaleX = this._Wsect_pix / this._Wsect_m;
+        this._scaleY = this._Hsect_pix / this._Hsect_m;
+        // origine
+        this._origX = (this._size - this._Wsect_pix) / 2;
+        this._origY = b ? this._bottomMargin : (this._size - this._Hsect_pix) / 2;
+    }
+
+    /**
+     * convertit une abscisse en m en pixels
+     */
+    private Xm2pix(x: number) {
+        return this._origX + x * this._scaleX;
+    }
+
+    /**
+     * convertit une ordonnée en m en pixels
+     */
+    private Ym2pix(y: number) {
+        return this._size - this._origY - y * this._scaleY;
+    }
+
+    public get useRealAspectRatio(): boolean {
+        return this._useRealAspectRatio;
     }
 
     public setUseRealAspectRatio(b: boolean) {
-        this.useRealAspectRatio = b;
+        this._useRealAspectRatio = b;
+        this.computeTransform();
         this.draw();
     }
 
+    private setLevels() {
+        this._levels = [];
+
+        // traduction des symboles des variables calculées
+        const re = this._result.resultElement;
+        if (re !== undefined) {
+            for (const k in re.values) {
+                if (k !== re.vCalcSymbol) {
+                    //const lbl = k.toUpperCase();
+                    const er = re.getValue(k);
+                    // this._resultElement.addExtraResult(lbl, er);
+
+                    if (this.isSectionLevel(k)) {
+                        this.addLevel(er, k + " = " + this.formattedValue(er), SectionCanvasComponent.labelColors[k]);
+                    }
+                }
+            }
+        }
+
+        // ajout du tirant d'eau saisi
+        const valY = this._result.sourceNub.getParameter("Y").singleValue;
+        this.addLevel(valY, "Y = " + this.formattedValue(valY), SectionCanvasComponent.labelColors["Y"]);
+
+        this.sortLevels();
+    }
+
     private addLevel(val: number, label: string, rgb: {}) {
         this._levels.push({ val, label, rgb });
     }
 
+    private sortLevels() {
+        this._levels.sort((a, b) => {
+            if (a["val"] < b["val"]) {
+                return -1;
+            }
+            if (a["val"] > b["val"]) {
+                return 1;
+            }
+            return 0;
+        });
+    }
+
     // max des niveaux à représenter
     private getMaxLevel(): number {
         // max de la cote de berge et des niveaux (qui sont triés)
@@ -193,33 +289,8 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
     }
 
     public draw() {
-        // console.log(">> redrawing at size", this._size);
         if (this._context2d && this._section) {
-            this.reset();
-
-            // traduction des symboles des variables calculées
-            const re = this._result.resultElement;
-            if (re !== undefined) {
-                for (const k in re.values) {
-                    if (k !== re.vCalcSymbol) {
-                        //const lbl = k.toUpperCase();
-                        const er = re.getValue(k);
-                        // this._resultElement.addExtraResult(lbl, er);
-
-                        if (this.isSectionLevel(k)) {
-                            this.addLevel(er, k + " = " + this.formattedValue(er), SectionCanvasComponent.labelColors[k]);
-                        }
-                    }
-                }
-            }
-
-            // ajout du tirant d'eau saisi
-            const valY = this._result.sourceNub.getParameter("Y").singleValue;
-            this.addLevel(valY, "Y = " + this.formattedValue(valY), SectionCanvasComponent.labelColors["Y"]);
-
-            this.computeSectionHeight();
-            this.computeRenderSize();
-            this.computeScale();
+            this.clear();
             setTimeout(() => { // à cause du changement de taille du canvas dans updateCanvasSize()
                 this.drawFrame();
                 this.drawSection();
@@ -234,19 +305,22 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
      * yb : cote de berge
      * maxHeight : valeur maxi des cotes
      */
-    private drawTopDashLines(xmin: number, xmax: number, yb: number, maxHeight: number) {
+    private drawTopDashLines(xmin: number, xmax: number, yb: number) {
         this.setLineWidth(2);
         this.setLineDash([5]);
         this.setStrokeColor(128, 128, 128);
-        this.drawSectionLine(xmin, yb, xmin, maxHeight);
-        this.drawSectionLine(xmax, yb, xmax, maxHeight);
+        const x1 = this.Xm2pix(xmin);
+        const ybp = this.Ym2pix(yb);
+        this.drawLine(x1, ybp, x1, 0);
+        const x2 = this.Xm2pix(xmax);
+        this.drawLine(x2, ybp, x2, 0);
     }
 
     private computeSectionHeight() {
-        this.sortLevels();
+        this.setLevels();
 
         // hauteur totale de la section
-        this._sectionHeight = this.getMaxLevel() * 1.1;
+        this._Hsect_m = this.getMaxLevel();
     }
 
     private computeSectionWidthTrapez() {
@@ -257,7 +331,7 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
         const lp: number = prms.Fruit.v * prms.YB.v;
 
         // largeur totale de la section
-        this._sectionWidth = lp * 2 + prms.LargeurFond.v;
+        this._Wsect_m = lp * 2 + prms.LargeurFond.v;
     }
 
     private drawSectionTrapez() {
@@ -276,11 +350,11 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
         this.setLineWidth(5);
         this.drawSectionLine(0, yb, lp, 0);
         this.drawSectionLine(lp, 0, lp + prms.LargeurFond.v, 0);
-        this.drawSectionLine(lp + prms.LargeurFond.v, 0, this._sectionWidth, yb);
+        this.drawSectionLine(lp + prms.LargeurFond.v, 0, this._Wsect_m, yb);
 
         // pointillés du haut
 
-        this.drawTopDashLines(0, this._sectionWidth, yb, this._sectionHeight);
+        this.drawTopDashLines(0, this._Wsect_m, yb);
     }
 
     private computeSectionWidthRect() {
@@ -288,7 +362,7 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
         const prms: ParamsSectionRectang = <ParamsSectionRectang>sect.prms;
 
         // largeur totale de la section
-        this._sectionWidth = prms.LargeurBerge.v;
+        this._Wsect_m = prms.LargeurBerge.v;
     }
 
     private drawSectionRect() {
@@ -304,12 +378,12 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
         this.setStrokeColor(0, 0, 0);
         this.setLineWidth(5);
         this.drawSectionLine(0, yb, 0, 0);
-        this.drawSectionLine(0, 0, this._sectionWidth, 0);
-        this.drawSectionLine(this._sectionWidth, 0, this._sectionWidth, yb);
+        this.drawSectionLine(0, 0, this._Wsect_m, 0);
+        this.drawSectionLine(this._Wsect_m, 0, this._Wsect_m, yb);
 
         // pointillés du haut
 
-        this.drawTopDashLines(0, this._sectionWidth, yb, this._sectionHeight);
+        this.drawTopDashLines(0, this._Wsect_m, yb);
     }
 
     private computeSectionWidthCirc() {
@@ -330,7 +404,7 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
         }
 
         // largeur totale de la section
-        this._sectionWidth = yb < r ? B.vCalc : D;
+        this._Wsect_m = yb < r ? B.vCalc : D;
     }
 
     private drawSectionCirc() {
@@ -356,7 +430,7 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
             this.setStrokeColor(0, 0, 0);
             this.setLineWidth(5);
 
-            const wx: number = this._sectionWidth / 2;
+            const wx: number = this._Wsect_m / 2;
             const alpha: Result = sect.CalcSection("Alpha", yb);
             if (!alpha.ok) {
                 throw alpha;
@@ -369,7 +443,7 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
             // pointillés du haut
 
             const w: number = yb > r ? (D - B.vCalc) / 2 : 0;
-            this.drawTopDashLines(w, this._sectionWidth - w, yb, this._sectionHeight);
+            this.drawTopDashLines(w, this._Wsect_m - w, yb);
         } catch (e) {
             const res: Result = e as Result;
             this.drawText("error : " + res.log.toString(), 0, 0);
@@ -384,7 +458,7 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
         const B: number = prms.LargeurBerge.v;
 
         // largeur totale de la section
-        this._sectionWidth = B;
+        this._Wsect_m = B;
     }
 
     private drawSectionPara() {
@@ -414,7 +488,7 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
         this._context2d.stroke();
 
         // pointillés du haut
-        this.drawTopDashLines(0, this._sectionWidth, yb, this._sectionHeight);
+        this.drawTopDashLines(0, this._Wsect_m, yb);
     }
 
     private drawSectionEllipse(x: number, y: number, rX: number, rY: number, rot: number, start: number, end: number) {
@@ -459,43 +533,6 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
             throw new Error("SectionCanvasComponent.drawSection() : type de section non pris en charge");
     }
 
-    private computeScale() {
-        this._scaleX = this._renderSectionX / this._sectionWidth;
-        this._scaleY = this._renderSectionY / this._sectionHeight;
-    }
-
-    /**
-     * convertit une abscisse en m en pixels
-     */
-    private Xm2pix(x: number) {
-        // origine X de la section dans le canvas
-        const origX = (this._size - this._renderSectionX) / 2;
-
-        return origX + x * this._scaleX;
-    }
-
-    /**
-     * convertit une ordonnée en m en pixels
-     */
-    private Ym2pix(y: number) {
-        // origine Y de la section dans le canvas
-        const origY = (this._size - this._renderSectionY) / 2;
-
-        return this._size - this._bottomMargin - origY - y * this._scaleY;
-    }
-
-    private sortLevels() {
-        this._levels.sort((a, b) => {
-            if (a["val"] < b["val"]) {
-                return -1;
-            }
-            if (a["val"] > b["val"]) {
-                return 1;
-            }
-            return 0;
-        });
-    }
-
     private drawLevels() {
         let left = true;
 
@@ -506,13 +543,13 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
             const y = l["val"];
             const col = l["rgb"];
             this.setStrokeColor(col["r"], col["g"], col["b"]);
-            this.drawSectionLine(0, y, this._sectionWidth, y);
+            this.drawSectionLine(0, y, this._Wsect_m, y);
 
             this.setFillColor(col["r"], col["g"], col["b"]);
             if (left) {
                 this.drawText(l["label"], 0, y, "right");
             } else {
-                this.drawText(l["label"], this._sectionWidth, y, "left");
+                this.drawText(l["label"], this._Wsect_m, y, "left");
             }
             left = !left;
         }
-- 
GitLab


From 02a019d0f0f0b633499a997e8e49dff799fc468f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr>
Date: Thu, 6 Oct 2022 12:05:27 +0200
Subject: [PATCH 4/5] fix: parametric sections graph: overlapping levels text

refs #497
---
 .../section-canvas.component.ts               | 67 ++++++++++++++++---
 1 file changed, 56 insertions(+), 11 deletions(-)

diff --git a/src/app/components/section-canvas/section-canvas.component.ts b/src/app/components/section-canvas/section-canvas.component.ts
index 0c7a71635..cc5f23320 100644
--- a/src/app/components/section-canvas/section-canvas.component.ts
+++ b/src/app/components/section-canvas/section-canvas.component.ts
@@ -241,6 +241,9 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
         this._levels.push({ val, label, rgb });
     }
 
+    /**
+     * trie les tirants par niveau d'eau croissant
+     */
     private sortLevels() {
         this._levels.sort((a, b) => {
             if (a["val"] < b["val"]) {
@@ -533,26 +536,68 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
             throw new Error("SectionCanvasComponent.drawSection() : type de section non pris en charge");
     }
 
-    private drawLevels() {
-        let left = true;
+    /**
+     * dessin des niveaux en gérant le chevauchement
+     * @param levels liste des niveaux à tracer
+     * @param textHeight hauteur minimal entre le texte des niveaux (m)
+     * @param left true pour tracer le texte à gauche du niveau, false à droite
+     */
+    private drawLevelsWithoutOverlap(levels: any, textHeight: number, left: boolean) {
+        for (let i = levels.length - 1; i >= 0; i--) {
+            const l = levels[i];
 
+            // chevauchement avec le précédent ?
+            if (i < levels.length - 1) {
+                let yprec = levels[i + 1].y;
+
+                const ycurr = l.y;
+                if (yprec - ycurr < textHeight) {
+                    l.y = yprec - textHeight;
+                }
+            }
+
+            // tracé du tirant courant
+            const col = l["rgb"];
+            this.setStrokeColor(col["r"], col["g"], col["b"]);
+            this.drawSectionLine(0, l.val, this._Wsect_m, l.val);
+            this.setFillColor(col["r"], col["g"], col["b"]);
+
+            if (left) {
+                this.drawText(l["label"], 0, l.y, "right");
+            } else {
+                this.drawText(l["label"], this._Wsect_m, l.y, "left");
+            }
+        }
+    }
+
+    private drawLevels() {
         this.resetLineDash();
         this.setLineWidth(1);
-        this.setFont("12px sans- serif");
+        this.setFont("12px sans-serif");
+
+        // hauteur des caractères
+        const tm: TextMetrics = this._context2d.measureText("Ag");
+        const charHeightPix = tm.actualBoundingBoxAscent + tm.actualBoundingBoxDescent;
+        const charHeightMeter = charHeightPix / this._scaleY;
+
+        // sépare les niveaux de gauche/droite
+        const leftLevels = [];
+        const rightLevels = [];
+        let left = true;
         for (const l of this._levels) {
             const y = l["val"];
-            const col = l["rgb"];
-            this.setStrokeColor(col["r"], col["g"], col["b"]);
-            this.drawSectionLine(0, y, this._Wsect_m, y);
-
-            this.setFillColor(col["r"], col["g"], col["b"]);
+            Object.assign(l, { "y": y }); // y = ordonnée de tracé
             if (left) {
-                this.drawText(l["label"], 0, y, "right");
+                leftLevels.push(l);
             } else {
-                this.drawText(l["label"], this._Wsect_m, y, "left");
+                rightLevels.push(l);
             }
             left = !left;
         }
+
+        // dessin des textes
+        this.drawLevelsWithoutOverlap(leftLevels, charHeightMeter, true);
+        this.drawLevelsWithoutOverlap(rightLevels, charHeightMeter, false);
     }
 
     // contour du canvas
@@ -578,7 +623,7 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements
         this._context2d.fillStyle = col;
     }
 
-    public setFont(f: string) {
+    private setFont(f: string) {
         this._context2d.font = f;
     }
 
-- 
GitLab


From 16435bba52b5ba2c9c1424373e4fe9df5dd6a14e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr>
Date: Thu, 6 Oct 2022 14:55:54 +0200
Subject: [PATCH 5/5] update jalhyd_branch to devel

refs #497
---
 jalhyd_branch | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/jalhyd_branch b/jalhyd_branch
index 626e97d71..d64531f13 100644
--- a/jalhyd_branch
+++ b/jalhyd_branch
@@ -1 +1 @@
-devel
\ No newline at end of file
+devel
-- 
GitLab