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] 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