diff --git a/package-lock.json b/package-lock.json
index 3accb69910f955df51cbfe025e041f79c68e947f..1df2daaff135bdcb9ffa576532a181ac6c10b43d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -25,9 +25,8 @@
         "@ngx-matomo/tracker": "^3.0.0",
         "@types/pako": "^1.0.4",
         "@types/sprintf-js": "^1.1.2",
-        "angular2-chartjs": "^0.5.1",
         "angular2-hotkeys": "^13.1.0",
-        "chartjs-plugin-zoom": "^0.7.7",
+        "chartjs-plugin-zoom": "^1.2.1",
         "cordova-android": "^11.0.0",
         "cordova-plugin-advanced-http": "^3.3.1",
         "cordova-plugin-app-version": "^0.1.14",
@@ -44,6 +43,7 @@
         "material-design-icons": "^3.0.1",
         "mathjax": "^3.2.2",
         "mermaid": "^9.1.3",
+        "ng2-charts": "^4.0.0",
         "ngx-markdown": "^14.0.1",
         "ngx-material-file-input": "^4.0.0",
         "ngx-webstorage-service": "^5.0.0",
@@ -4444,18 +4444,6 @@
         "semver": "bin/semver"
       }
     },
-    "node_modules/angular2-chartjs": {
-      "version": "0.5.1",
-      "license": "MIT",
-      "dependencies": {
-        "chart.js": "^2.3.0"
-      },
-      "peerDependencies": {
-        "@angular/common": ">=4.0.0 || ^2.0.0",
-        "@angular/compiler": ">=4.0.0 || ^2.0.0",
-        "@angular/core": ">=4.0.0 || ^2.0.0"
-      }
-    },
     "node_modules/angular2-hotkeys": {
       "version": "13.1.0",
       "license": "MIT",
@@ -5873,36 +5861,20 @@
       "license": "MIT"
     },
     "node_modules/chart.js": {
-      "version": "2.9.4",
-      "license": "MIT",
-      "dependencies": {
-        "chartjs-color": "^2.1.0",
-        "moment": "^2.10.2"
-      }
-    },
-    "node_modules/chartjs-color": {
-      "version": "2.4.1",
-      "license": "MIT",
-      "dependencies": {
-        "chartjs-color-string": "^0.6.0",
-        "color-convert": "^1.9.3"
-      }
-    },
-    "node_modules/chartjs-color-string": {
-      "version": "0.6.0",
-      "license": "MIT",
-      "dependencies": {
-        "color-name": "^1.0.0"
-      }
+      "version": "3.9.1",
+      "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.9.1.tgz",
+      "integrity": "sha512-Ro2JbLmvg83gXF5F4sniaQ+lTbSv18E+TIf2cOeiH1Iqd2PGFOtem+DUufMZsCJwFE7ywPOpfXFBwRTGq7dh6w==",
+      "peer": true
     },
     "node_modules/chartjs-plugin-zoom": {
-      "version": "0.7.7",
-      "license": "MIT",
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/chartjs-plugin-zoom/-/chartjs-plugin-zoom-1.2.1.tgz",
+      "integrity": "sha512-2zbWvw2pljrtMLMXkKw1uxYzAne5PtjJiOZftcut4Lo3Ee8qUt95RpMKDWrZ+pBZxZKQKOD/etdU4pN2jxZUmg==",
       "dependencies": {
         "hammerjs": "^2.0.8"
       },
       "peerDependencies": {
-        "chart.js": "^2.6.0"
+        "chart.js": "^3.2.0"
       }
     },
     "node_modules/cheerio": {
@@ -13362,6 +13334,11 @@
       "version": "4.17.21",
       "license": "MIT"
     },
+    "node_modules/lodash-es": {
+      "version": "4.17.21",
+      "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
+      "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="
+    },
     "node_modules/lodash.debounce": {
       "version": "4.0.8",
       "license": "MIT"
@@ -13893,13 +13870,6 @@
         "node": ">=10"
       }
     },
-    "node_modules/moment": {
-      "version": "2.29.4",
-      "license": "MIT",
-      "engines": {
-        "node": "*"
-      }
-    },
     "node_modules/moment-mini": {
       "version": "2.24.0",
       "license": "MIT"
@@ -14021,6 +13991,21 @@
       "dev": true,
       "license": "ISC"
     },
+    "node_modules/ng2-charts": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/ng2-charts/-/ng2-charts-4.0.0.tgz",
+      "integrity": "sha512-1COLMs1UH8XIurk9C3pBQW3zH4RM3ggPtaC5vGjEmRGZ2cK/j8DqpzN4xMqyk0KB4D2vw/ZejgXmxxZ4Ie58Rw==",
+      "dependencies": {
+        "lodash-es": "^4.17.15",
+        "tslib": "^2.3.0"
+      },
+      "peerDependencies": {
+        "@angular/common": ">=14.0.0",
+        "@angular/core": ">=14.0.0",
+        "chart.js": "^3.4.0",
+        "rxjs": "^6.5.3 || ^7.4.0"
+      }
+    },
     "node_modules/ngx-markdown": {
       "version": "14.0.1",
       "license": "MIT",
@@ -22809,12 +22794,6 @@
         }
       }
     },
-    "angular2-chartjs": {
-      "version": "0.5.1",
-      "requires": {
-        "chart.js": "^2.3.0"
-      }
-    },
     "angular2-hotkeys": {
       "version": "13.1.0",
       "requires": {
@@ -23741,27 +23720,15 @@
       "version": "0.7.0"
     },
     "chart.js": {
-      "version": "2.9.4",
-      "requires": {
-        "chartjs-color": "^2.1.0",
-        "moment": "^2.10.2"
-      }
-    },
-    "chartjs-color": {
-      "version": "2.4.1",
-      "requires": {
-        "chartjs-color-string": "^0.6.0",
-        "color-convert": "^1.9.3"
-      }
-    },
-    "chartjs-color-string": {
-      "version": "0.6.0",
-      "requires": {
-        "color-name": "^1.0.0"
-      }
+      "version": "3.9.1",
+      "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.9.1.tgz",
+      "integrity": "sha512-Ro2JbLmvg83gXF5F4sniaQ+lTbSv18E+TIf2cOeiH1Iqd2PGFOtem+DUufMZsCJwFE7ywPOpfXFBwRTGq7dh6w==",
+      "peer": true
     },
     "chartjs-plugin-zoom": {
-      "version": "0.7.7",
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/chartjs-plugin-zoom/-/chartjs-plugin-zoom-1.2.1.tgz",
+      "integrity": "sha512-2zbWvw2pljrtMLMXkKw1uxYzAne5PtjJiOZftcut4Lo3Ee8qUt95RpMKDWrZ+pBZxZKQKOD/etdU4pN2jxZUmg==",
       "requires": {
         "hammerjs": "^2.0.8"
       }
@@ -28676,6 +28643,11 @@
     "lodash": {
       "version": "4.17.21"
     },
+    "lodash-es": {
+      "version": "4.17.21",
+      "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
+      "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="
+    },
     "lodash.debounce": {
       "version": "4.0.8"
     },
@@ -28991,9 +28963,6 @@
     "mkdirp": {
       "version": "1.0.4"
     },
-    "moment": {
-      "version": "2.29.4"
-    },
     "moment-mini": {
       "version": "2.24.0"
     },
@@ -29079,6 +29048,15 @@
       "version": "1.1.0",
       "dev": true
     },
+    "ng2-charts": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/ng2-charts/-/ng2-charts-4.0.0.tgz",
+      "integrity": "sha512-1COLMs1UH8XIurk9C3pBQW3zH4RM3ggPtaC5vGjEmRGZ2cK/j8DqpzN4xMqyk0KB4D2vw/ZejgXmxxZ4Ie58Rw==",
+      "requires": {
+        "lodash-es": "^4.17.15",
+        "tslib": "^2.3.0"
+      }
+    },
     "ngx-markdown": {
       "version": "14.0.1",
       "requires": {
diff --git a/package.json b/package.json
index f9a1a962c6fd968d975d6031441cd5e4b91a8fe6..24abe266b331a17b8ed186399cb51f03809b9105 100644
--- a/package.json
+++ b/package.json
@@ -51,9 +51,9 @@
     "@ngx-matomo/tracker": "^3.0.0",
     "@types/pako": "^1.0.4",
     "@types/sprintf-js": "^1.1.2",
-    "angular2-chartjs": "^0.5.1",
+    "ng2-charts": "^4.0.0",
     "angular2-hotkeys": "^13.1.0",
-    "chartjs-plugin-zoom": "^0.7.7",
+    "chartjs-plugin-zoom": "^1.2.1",
     "cordova-android": "^11.0.0",
     "cordova-plugin-advanced-http": "^3.3.1",
     "cordova-plugin-app-version": "^0.1.14",
diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index 468ee73c90db11b7388b49f6d0b2adc719a8fe72..7c57cdce8f41945363e18863eb2a1122c4a7b940 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -41,7 +41,7 @@ import {
 
 import { HttpClientModule } from "@angular/common/http";
 import { FormsModule, ReactiveFormsModule } from "@angular/forms"; // <-- NgModel lives here
-import { ChartModule } from "angular2-chartjs";
+import { NgChartsModule } from "ng2-charts";
 import { RouterModule, Routes } from "@angular/router";
 import { HotkeyModule } from "angular2-hotkeys";
 import { NgxMatomoTrackerModule } from "@ngx-matomo/tracker";
@@ -138,7 +138,7 @@ const appRoutes: Routes = [
         ReactiveFormsModule,
         BrowserAnimationsModule,
         BrowserModule,
-        ChartModule,
+        NgChartsModule,
         DragDropModule,
         FlexLayoutModule,
         HotkeyModule.forRoot(),
diff --git a/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.html b/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.html
index 9bc8e3bb104543f2a70712755bdc96d76ce18226..76aefb4b68bd64ccfc04c2cc4e8570decf0d2de4 100644
--- a/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.html
+++ b/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.html
@@ -116,8 +116,8 @@
 </div>
 
 <div mat-dialog-content *ngIf="viewChart">
-    <chart id="values-chart" type="scatter" [data]="chartData" [options]="chartOptions">
-    </chart>
+    <canvas baseChart id="values-chart" type="scatter" [data]="chartData" [options]="chartOptions">
+    </canvas>
 </div>
 
 <div mat-dialog-actions [attr.align]="'end'">
diff --git a/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.ts b/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.ts
index 7f28b26ddab5397d2453fb115a0c019d286b4ba5..a5cc9fcecbac2ac9ab0baa1346c43253a4c73d09 100644
--- a/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.ts
+++ b/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.ts
@@ -107,34 +107,36 @@ export class DialogEditParamValuesComponent implements OnInit {
             animation: {
                 duration: 0
             },
-            legend: {
-                display: false
-            },
             scales: {
-                xAxes: [{
+                x: {
                     type: "linear",
                     position: "bottom",
                     ticks: {
                         precision: ResultsComponentDirective.CHARTS_AXIS_PRECISION
                     }
-                }],
-                yAxes: [{
+                },
+                y: {
                     type: "linear",
                     position: "left",
                     ticks: {
                         precision: ResultsComponentDirective.CHARTS_AXIS_PRECISION
                     }
-                }]
+                }
             },
             elements: {
                 line: {
                     tension: 0
                 }
             },
-            tooltips: {
-                callbacks: {
-                    label: function(tooltipItem) {
-                        return  fv(Number(tooltipItem.yLabel));
+            plugins: {
+                legend: {
+                    display: false
+                },
+                tooltip: {
+                    callbacks: {
+                        label: function (tooltipItem) {
+                            return fv(Number(tooltipItem.formattedValue));
+                        }
                     }
                 }
             }
diff --git a/src/app/components/jet-trajectory-chart/jet-trajectory-chart.component.html b/src/app/components/jet-trajectory-chart/jet-trajectory-chart.component.html
index cedbcf29399b1b64c0fc89833f8b4cbee6e55830..045e8b49d0e2f618fdffee3ed41a358fc950d61b 100644
--- a/src/app/components/jet-trajectory-chart/jet-trajectory-chart.component.html
+++ b/src/app/components/jet-trajectory-chart/jet-trajectory-chart.component.html
@@ -17,7 +17,7 @@
         </div>
 
         <div *ngIf="! displayChart" class="fake-chart"></div><!-- trick to avoid blinking effect due to forceRebuild -->
-        <chart *ngIf="displayChart" type="scatter" [data]="graph_data" [options]="graph_options">
-        </chart>
+        <canvas baseChart #chartcanvas="base-chart" *ngIf="displayChart" type="scatter" [data]="graph_data" [options]="graph_options">
+        </canvas>
     </div>
 </div>
\ No newline at end of file
diff --git a/src/app/components/jet-trajectory-chart/jet-trajectory-chart.component.ts b/src/app/components/jet-trajectory-chart/jet-trajectory-chart.component.ts
index 2d726e9f975d19f3075bc924800f867df01a1134..5bd87e2bb12d5177c109a493bcc92517bef823ce 100644
--- a/src/app/components/jet-trajectory-chart/jet-trajectory-chart.component.ts
+++ b/src/app/components/jet-trajectory-chart/jet-trajectory-chart.component.ts
@@ -1,6 +1,6 @@
 import { Component, ViewChild, ChangeDetectorRef, Input, OnChanges } from "@angular/core";
 
-import { ChartComponent } from "angular2-chartjs";
+import { BaseChartDirective } from "ng2-charts";
 
 import { I18nService } from "../../services/internationalisation.service";
 import { ResultsComponentDirective } from "../fixedvar-results/results.component";
@@ -10,6 +10,10 @@ import { AppComponent } from "../../app.component";
 
 import { Jet, Result } from "jalhyd";
 
+
+import zoomPlugin from 'chartjs-plugin-zoom';
+import { Chart } from "chart.js";
+
 @Component({
     selector: "jet-trajectory-chart",
     templateUrl: "./jet-trajectory-chart.component.html",
@@ -19,8 +23,8 @@ import { Jet, Result } from "jalhyd";
 })
 export class JetTrajectoryChartComponent extends ResultsComponentDirective implements OnChanges {
 
-    @ViewChild(ChartComponent)
-    private chartComponent;
+    @ViewChild('chartcanvas')
+    private chartComponent: BaseChartDirective;
 
     private _results: Result;
 
@@ -42,14 +46,16 @@ export class JetTrajectoryChartComponent extends ResultsComponentDirective imple
         animation: {
             duration: 0
         },
-        legend: {
-            display: true,
-            position: "bottom",
-            reverse: false
-        },
-        title: {
-            display: true,
-            text: this.intlService.localizeText("INFO_JET_TITRE_TRAJECTOIRE")
+        plugins: {
+            legend: {
+                display: true,
+                position: "bottom",
+                reverse: false
+            },
+            title: {
+                display: true,
+                text: this.intlService.localizeText("INFO_JET_TITRE_TRAJECTOIRE")
+            }
         },
         elements: {
             line: {
@@ -63,30 +69,31 @@ export class JetTrajectoryChartComponent extends ResultsComponentDirective imple
         private cd: ChangeDetectorRef
     ) {
         super();
+        Chart.register(zoomPlugin);
         // do not move following block out of constructor or scale labels won't be rendered
         this.graph_options["scales"] = {
-            xAxes: [{
+            x: {
                 type: "linear",
                 position: "bottom",
                 ticks: {
                     precision: ResultsComponentDirective.CHARTS_AXIS_PRECISION
                 },
-                scaleLabel: {
+                title: {
                     display: true,
-                    labelString: this.intlService.localizeText("INFO_LIB_ABSCISSE")
+                    text: this.intlService.localizeText("INFO_LIB_ABSCISSE")
                 }
-            }],
-            yAxes: [{
+            },
+            y: {
                 type: "linear",
                 position: "left",
                 ticks: {
                     precision: ResultsComponentDirective.CHARTS_AXIS_PRECISION
                 },
-                scaleLabel: {
+                title: {
                     display: true,
-                    labelString: this.intlService.localizeText("INFO_LIB_ALTITUDE")
+                    text: this.intlService.localizeText("INFO_LIB_ALTITUDE")
                 }
-            }]
+            }
         };
         // enable zoom and pan (using "chartjs-plugin-zoom" package)
         const that = this;
@@ -94,11 +101,10 @@ export class JetTrajectoryChartComponent extends ResultsComponentDirective imple
             zoom: {
                 pan: {
                     enabled: false, // conflicts with drag zoom
-                    mode: "xy",
                 },
                 zoom: {
-                    enabled: true,
                     drag: { // conflicts with pan; set to false to enable mouse wheel zoom,
+                        enabled: true,
                         borderColor: "rgba(225,225,225,0.3)",
                         borderWidth: 1,
                         backgroundColor: "rgba(0,0,0,0.25)"
@@ -110,12 +116,12 @@ export class JetTrajectoryChartComponent extends ResultsComponentDirective imple
                 }
             }
         };
-        // format numbers in tooltips
-        this.graph_options.tooltips = {
+        // format numbers in tooltip
+        this.graph_options.tooltip = {
             displayColors: false,
             callbacks: {
-                label: (tooltipItem, data) => {
-                    return "(" + fv(Number(tooltipItem.xLabel)) + ", " + fv(Number(tooltipItem.yLabel)) + ")";
+                label: (tooltipItem) => {
+                    return "(" + fv(Number(tooltipItem.label)) + ", " + fv(Number(tooltipItem.formattedValue)) + ")";
                 }
             }
         };
@@ -132,7 +138,7 @@ export class JetTrajectoryChartComponent extends ResultsComponentDirective imple
 
     @Input()
     public set results(r: Result) {
-        this.forceRebuild(); // used for forcing redefinition of xAxes[0].ticks.min/max in generateScatterChart()
+        this.forceRebuild(); // used for forcing redefinition of x.min/max in generateScatterChart()
         this._results = r;
     }
 
@@ -193,8 +199,8 @@ export class JetTrajectoryChartComponent extends ResultsComponentDirective imple
         }
 
         // adjust chart width
-        this.graph_options.scales.xAxes[0].ticks.min = 0;
-        this.graph_options.scales.xAxes[0].ticks.max = greatestAbscissa;
+        this.graph_options.scales.x.min = 0;
+        this.graph_options.scales.x.max = greatestAbscissa;
 
         // build Y data series
         for (const ys of ySeries) {
diff --git a/src/app/components/pab-profile-chart/pab-profile-chart.component.html b/src/app/components/pab-profile-chart/pab-profile-chart.component.html
index f7c4d9079569cf669e92ffecf1e18d01684b654b..873035f24e062ddb88b2d2fbf3fba87c0fab6fc0 100644
--- a/src/app/components/pab-profile-chart/pab-profile-chart.component.html
+++ b/src/app/components/pab-profile-chart/pab-profile-chart.component.html
@@ -16,7 +16,7 @@
             </button>
         </div>
 
-        <chart type="scatter" [data]="graph_data" [options]="graph_options">
-        </chart>
+        <canvas baseChart #chartcanvas="base-chart" type="scatter" [data]="graph_data" [options]="graph_options">
+        </canvas>
     </div>
 </div>
\ No newline at end of file
diff --git a/src/app/components/pab-profile-chart/pab-profile-chart.component.ts b/src/app/components/pab-profile-chart/pab-profile-chart.component.ts
index 449c050ffc94f34685a9aa280756ced6b9b051fc..35c943ea68f282f7571f17e8838c6d2b3a72c303 100644
--- a/src/app/components/pab-profile-chart/pab-profile-chart.component.ts
+++ b/src/app/components/pab-profile-chart/pab-profile-chart.component.ts
@@ -1,6 +1,6 @@
 import { Component, ViewChild, ChangeDetectorRef, Input, OnChanges } from "@angular/core";
 
-import { ChartComponent } from "angular2-chartjs";
+import { BaseChartDirective } from "ng2-charts";
 
 import { I18nService } from "../../services/internationalisation.service";
 import { ResultsComponentDirective } from "../fixedvar-results/results.component";
@@ -14,6 +14,9 @@ import { CloisonAval, Cloisons, LoiDebit } from "jalhyd";
 import { sprintf } from "sprintf-js";
 import { CalculatorResults } from 'app/results/calculator-results';
 
+import zoomPlugin from 'chartjs-plugin-zoom';
+import { Chart } from "chart.js";
+
 @Component({
     selector: "pab-profile-chart",
     templateUrl: "./pab-profile-chart.component.html",
@@ -23,8 +26,8 @@ import { CalculatorResults } from 'app/results/calculator-results';
 })
 export class PabProfileChartComponent extends ResultsComponentDirective implements OnChanges {
 
-    @ViewChild(ChartComponent)
-    private chartComponent;
+    @ViewChild('chartcanvas')
+    private chartComponent: BaseChartDirective;
 
     private _results: PabResults;
 
@@ -40,21 +43,23 @@ export class PabProfileChartComponent extends ResultsComponentDirective implemen
      * config du graphique
      */
     public graph_data: { datasets: any[] };
-    public graph_options = {
+    public graph_options: any = {
         responsive: true,
         maintainAspectRatio: true,
         aspectRatio: 1.5,
         animation: {
             duration: 0
         },
-        legend: {
-            display: true,
-            position: "bottom",
-            reverse: false
-        },
-        title: {
-            display: true,
-            text: this.intlService.localizeText("INFO_PAB_TITRE_PROFIL")
+        plugins: {
+            legend: {
+                display: true,
+                position: "bottom",
+                reverse: false
+            },
+            title: {
+                display: true,
+                text: this.intlService.localizeText("INFO_PAB_TITRE_PROFIL")
+            }
         },
         elements: {
             line: {
@@ -68,30 +73,31 @@ export class PabProfileChartComponent extends ResultsComponentDirective implemen
         private cd: ChangeDetectorRef
     ) {
         super();
+        Chart.register(zoomPlugin);
         // do not move following block out of constructor or scale labels won't be rendered
         this.graph_options["scales"] = {
-            xAxes: [{
+            x: {
                 type: "linear",
                 position: "bottom",
                 ticks: {
                     precision: ResultsComponentDirective.CHARTS_AXIS_PRECISION
                 },
-                scaleLabel: {
+                title: {
                     display: true,
-                    labelString: this.intlService.localizeText("INFO_LIB_DISTANCE_AMONT")
+                    text: this.intlService.localizeText("INFO_LIB_DISTANCE_AMONT")
                 }
-            }],
-            yAxes: [{
+            },
+            y: {
                 type: "linear",
                 position: "left",
                 ticks: {
                     precision: ResultsComponentDirective.CHARTS_AXIS_PRECISION
                 },
-                scaleLabel: {
+                title: {
                     display: true,
-                    labelString: this.intlService.localizeText("INFO_LIB_COTE")
+                    text: this.intlService.localizeText("INFO_LIB_COTE")
                 }
-            }]
+            }
         };
         // enable zoom and pan (using "chartjs-plugin-zoom" package)
         const that = this;
@@ -99,11 +105,10 @@ export class PabProfileChartComponent extends ResultsComponentDirective implemen
             zoom: {
                 pan: {
                     enabled: false, // conflicts with drag zoom
-                    mode: "xy",
                 },
                 zoom: {
-                    enabled: true,
                     drag: { // conflicts with pan; set to false to enable mouse wheel zoom,
+                        enabled: true,
                         borderColor: "rgba(225,225,225,0.3)",
                         borderWidth: 1,
                         backgroundColor: "rgba(0,0,0,0.25)"
@@ -115,12 +120,12 @@ export class PabProfileChartComponent extends ResultsComponentDirective implemen
                 }
             }
         };
-        // format numbers in tooltips
-        this.graph_options["tooltips"] = {
+        // format numbers in tooltip
+        this.graph_options["tooltip"] = {
             displayColors: false,
             callbacks: {
-                label: (tooltipItem, data) => {
-                    return "(" + fv(Number(tooltipItem.xLabel)) + ", " + fv(Number(tooltipItem.yLabel)) + ")";
+                label: (tooltipItem) => {
+                    return "(" + fv(Number(tooltipItem.label)) + ", " + fv(Number(tooltipItem.formattedValue)) + ")";
                 }
             }
         };
diff --git a/src/app/components/remous-results/line-and-chart-data.ts b/src/app/components/remous-results/line-and-chart-data.ts
index c0c7b1d17b1a6292f905fb1de97de6efba3f2e85..433e147f689e97ead4367d5ce43a93ae4b71e2d3 100644
--- a/src/app/components/remous-results/line-and-chart-data.ts
+++ b/src/app/components/remous-results/line-and-chart-data.ts
@@ -193,13 +193,15 @@ export class ChartData {
     /**
      * Dessigne une ligne droite entre y0 (abscisse 0) et ymax (abscisse max),
      * sans passer par les méthodes mapPoint() et mapY() utilisées dans drawLine
+     * @param fillArea true pour remplir la zone sous la ligne
+     * @param fillColor couleur de remplissage de la zone sous la ligne
      */
-    public drawSimpleLine(y0: number, ymax: number, prof: number, color: string, lbl: string, fillColor?: string) {
+    public drawSimpleLine(y0: number, ymax: number, prof: number, color: string, lbl: string, fillArea: boolean = false, fillColor?: string) {
         const l = this.newLine(prof);
         l.setPoint(0, y0);
         l.setPoint(this._longBief, ymax);
         l.data = {
-            label: lbl, fill: fillColor !== undefined, tension: 0, spanGaps: true,
+            label: lbl, fill: fillArea, tension: 0, spanGaps: true,
             borderColor: color, backgroundColor: fillColor, pointRadius: 0, showLine: "true"
         };
     }
diff --git a/src/app/components/remous-results/remous-results.component.html b/src/app/components/remous-results/remous-results.component.html
index 7f9efd5fd03a4a8827d85473bc660943f101a7c4..592644d6d1842bba2e88cdc542a4af7f3c6dc0c5 100644
--- a/src/app/components/remous-results/remous-results.component.html
+++ b/src/app/components/remous-results/remous-results.component.html
@@ -2,6 +2,9 @@
     fxLayoutAlign="center center">
     <div fxFlex="1 1 100%">
         <div class="remous-results-buttons">
+            <button mat-icon-button (click)="resetZoom1()" [disabled]="! zoom1WasChanged" [title]="uitextResetZoomTitle">
+                <mat-icon color="primary">replay</mat-icon>
+            </button>
             <button mat-icon-button (click)="exportAsImage(remousResults)" [title]="uitextExportImageTitle">
                 <mat-icon color="primary">image</mat-icon>
             </button>
@@ -14,9 +17,9 @@
             </button>
         </div>
 
-        <chart id="main-chart" ngClass.lt-sm="height300" ngClass.sm="height400" ngClass.md="height400"
-            ngClass.gt-md="height600" [type]="graph1_type" [data]="graph1_data" [options]="graph1_options">
-        </chart>
+        <canvas baseChart #chartcanvas1="base-chart" id="main-chart" ngClass.lt-sm="height300" ngClass.sm="height400"
+            ngClass.md="height400" ngClass.gt-md="height600" [type]="graph1_type" [data]="graph1_data" [options]="graph1_options">
+        </canvas>
     </div>
 </div>
 
@@ -24,6 +27,9 @@
     fxLayoutAlign="center center">
     <div fxFlex="1 1 100%">
         <div class="remous-results-buttons">
+            <button mat-icon-button (click)="resetZoom2()" [disabled]="! zoom2WasChanged" [title]="uitextResetZoomTitle">
+                <mat-icon color="primary">replay</mat-icon>
+            </button>
             <button mat-icon-button (click)="exportAsImage(remousResultsExtra)" [title]="uitextExportImageTitle">
                 <mat-icon color="primary">image</mat-icon>
             </button>
@@ -36,7 +42,7 @@
             </button>
         </div>
 
-        <chart [type]="graph2_type" [data]="graph2_data" [options]="graph2_options"></chart>
+        <canvas baseChart #chartcanvas2="base-chart" [type]="graph2_type" [data]="graph2_data" [options]="graph2_options"></canvas>
     </div>
 </div>
 
diff --git a/src/app/components/remous-results/remous-results.component.ts b/src/app/components/remous-results/remous-results.component.ts
index b753778b459b0fd9db99057765b099cecfc82bc5..88a38d36647ccd4aee85a011001154ac7898e943 100644
--- a/src/app/components/remous-results/remous-results.component.ts
+++ b/src/app/components/remous-results/remous-results.component.ts
@@ -1,4 +1,4 @@
-import { Component, Input, OnChanges, SimpleChanges } from "@angular/core";
+import { ChangeDetectorRef, Component, Input, OnChanges, SimpleChanges, ViewChild } from "@angular/core";
 
 import { INumberIterator, CourbeRemousParams, CourbeRemous, ParamDefinition, ParamDomainValue, cLog } from "jalhyd";
 
@@ -12,6 +12,10 @@ import { LineData, ChartData } from "./line-and-chart-data";
 import { fv } from "../../util";
 import { VarResults } from "../../results/var-results";
 
+import { BaseChartDirective } from "ng2-charts";
+import zoomPlugin from 'chartjs-plugin-zoom';
+import { Chart } from "chart.js";
+
 @Component({
     selector: "remous-results",
     templateUrl: "./remous-results.component.html",
@@ -23,6 +27,16 @@ export class RemousResultsComponent extends ResultsComponentDirective implements
 
     private _remousResults: RemousResults;
 
+    @ViewChild('chartcanvas1')
+    private chartComponent1: BaseChartDirective;
+
+    @ViewChild('chartcanvas2')
+    private chartComponent2: BaseChartDirective;
+
+    private _zoom1WasChanged = false;
+
+    private _zoom2WasChanged = false;
+
     /*
     * config du graphique principal
     */
@@ -44,9 +58,11 @@ export class RemousResultsComponent extends ResultsComponentDirective implements
 
     constructor(
         private intlService: I18nService,
-        private formService: FormulaireService
+        private formService: FormulaireService,
+        private cd: ChangeDetectorRef
     ) {
         super();
+        Chart.register(zoomPlugin);
     }
 
     public get remousResults() {
@@ -272,18 +288,18 @@ export class RemousResultsComponent extends ResultsComponentDirective implements
         }
 
         // ligne de fond
-        gr1.drawSimpleLine(ZF1, ZF2, 3, "#753F00", this.uitextFond, "#753F00");
+        gr1.drawSimpleLine(ZF1, ZF2, 3, "#753F00", this.uitextFond, true, "#753F00");
 
         // ligne de berge
         if (hauteurBerge) {
-            gr1.drawSimpleLine(ZF1 + hauteurBerge, ZF2 + hauteurBerge, 4, "#C58F50", this.uitextBerge);
+            gr1.drawSimpleLine(ZF1 + hauteurBerge, ZF2 + hauteurBerge, 4, "#C58F50", this.uitextBerge, false, "#C58F50");
         }
 
         // hauteur normale
         if (this._remousResults.hautNormale?.ok) {
             const Yn = this._remousResults.hautNormale.vCalc;
             gr1.drawSimpleLine(Yn + ZF1, Yn + ZF2,
-                5, "#A4C537", this.uitextTirantNormal
+                5, "#A4C537", this.uitextTirantNormal, false, "#A4C537"
             );
         }
 
@@ -291,7 +307,7 @@ export class RemousResultsComponent extends ResultsComponentDirective implements
         if (this._remousResults.hautCritique?.ok) {
             const Yc = this._remousResults.hautCritique.vCalc;
             gr1.drawSimpleLine(Yc + ZF1, Yc + ZF2,
-                6, "#FF0000", this.uitextTirantCritique
+                6, "#FF0000", this.uitextTirantCritique, false, "#FF0000"
             );
         }
 
@@ -348,11 +364,12 @@ export class RemousResultsComponent extends ResultsComponentDirective implements
             }
         }
 
+        const extraLineColor = "#0093BD";
         if (this._remousResults.hasExtra) {
             if (this._remousResults.extraChart) {
                 lineExtra.data = {
                     label: this.extraParamLabel,
-                    tension: 0, spanGaps: true, borderColor: "#0093BD", pointRadius: 4
+                    tension: 0, spanGaps: true, borderColor: extraLineColor
                 };
             } else {
                 lineExtra.data = {
@@ -365,6 +382,9 @@ export class RemousResultsComponent extends ResultsComponentDirective implements
         // raccordement ligne fluviale -> torrentielle pour dessiner le ressaut
         this.connectRessaut(lineFlu, lineTor);
 
+        // couleur de la zone sous la ligne
+        const lineAreaColor = "rgba(209,208,212,0.5)";
+
         // ajout des données au graphique
         if (lineTor !== undefined) {
             lineTor.data = {
@@ -373,7 +393,7 @@ export class RemousResultsComponent extends ResultsComponentDirective implements
                 borderColor: "#77A3CD",
                 pointBackgroundColor: "#77A3CD",
                 pointRadius: 4,
-                backgroundColor: "#D1D0D4",
+                backgroundColor: lineAreaColor,
                 showLine: "true"
             };
         }
@@ -384,25 +404,22 @@ export class RemousResultsComponent extends ResultsComponentDirective implements
                 borderColor: "#0093BD",
                 pointBackgroundColor: "#0093BD",
                 pointRadius: 4,
-                backgroundColor: "#D1D0D4",
+                backgroundColor: lineAreaColor,
                 showLine: "true"
             };
         }
 
         this.graph1_data = gr1.data;
 
+        const that = this;
         this.graph1_options = {
             responsive: true,
-            maintainAspectRatio: false,
+            maintainAspectRatio: true,
             animation: {
                 duration: 0
             },
-            legend: {
-                display: true,
-                position: "bottom"
-            },
             scales: {
-                xAxes: [{
+                x: {
                     gridLines: {
                         display: true,
                         color: "rgba(255,99,132,0.2)",
@@ -410,29 +427,55 @@ export class RemousResultsComponent extends ResultsComponentDirective implements
                     },
                     ticks: {
                         precision: ResultsComponentDirective.CHARTS_AXIS_PRECISION,
-                        callback: function(value, index, values) {
+                        callback: function (value, index, values) {
                             return fv(Number(value));
                         }
                     },
-                    scaleLabel: {
+                    title: {
                         display: true,
-                        labelString: this.uitextAbscisse
+                        text: this.uitextAbscisse
                     }
-                }],
-                yAxes: [{
+                },
+                y: {
                     // stacked: true,
                     gridLines: {
-                      display: true,
-                      color: "rgba(255,99,132,0.2)"
+                        display: true,
+                        color: "rgba(255,99,132,0.2)"
                     }
-                }]
+                }
             },
-            tooltips: {
-                callbacks: {
-                    label: function(tooltipItem, data) {
-                        return fv(Number(tooltipItem.yLabel));
+            plugins: {
+                legend: {
+                    display: true,
+                    position: "bottom"
+                },
+                tooltip: {
+                    callbacks: {
+                        label: function (tooltipItem) {
+                            return fv(Number(tooltipItem.formattedValue));
+                        }
+                    }
+                },
+                zoom: {
+                    pan: {
+                        enabled: false,
+                    },
+                    zoom: {
+                        drag: {
+                            enabled: true,
+                            borderColor: "rgba(225,225,225,0.3)",
+                            borderWidth: 1,
+                            backgroundColor: "rgba(0,0,0,0.25)"
+                        },
+                        mode: 'xy',
+                        onZoomComplete: function (t: any) { return function () { t.zoom1Complete(); }; }(that)
                     }
                 }
+            },
+            elements: {
+                line: {
+                    fill: true
+                }
             }
         };
 
@@ -445,29 +488,58 @@ export class RemousResultsComponent extends ResultsComponentDirective implements
                 animation: {
                     duration: 0
                 },
-                legend: {
-                    display: true,
-                    position: "bottom"
-                },
                 scales: {
-                    xAxes: [{
-                        scaleLabel: {
+                    x: {
+                        title: {
                             display: true,
-                            labelString: this.uitextAbscisse
+                            text: this.uitextAbscisse
                         },
                         ticks: {
                             precision: ResultsComponentDirective.CHARTS_AXIS_PRECISION,
-                            callback: function(value, index, values) {
+                            callback: function (value, index, values) {
                                 return fv(Number(value));
                             }
                         },
-                    }]
+                    }
                 },
-                tooltips: {
-                    callbacks: {
-                        label: function(tooltipItem, data) {
-                            return fv(Number(tooltipItem.yLabel));
+                plugins: {
+                    legend: {
+                        display: true,
+                        position: "bottom"
+                    },
+                    tooltip: {
+                        callbacks: {
+                            label: function (tooltipItem) {
+                                return fv(Number(tooltipItem.formattedValue));
+                            }
                         }
+                    },
+                    zoom: {
+                        pan: {
+                            enabled: false,
+                        },
+                        zoom: {
+                            drag: {
+                                enabled: true,
+                                borderColor: "rgba(225,225,225,0.3)",
+                                borderWidth: 1,
+                                backgroundColor: "rgba(0,0,0,0.25)"
+                            },
+                            mode: 'xy',
+                            onZoomComplete: function (t: any) { return function () { t.zoom2Complete(); }; }(that)
+                        }
+                    }
+                },
+                elements: {
+                    line: {
+                        fill: true,
+                        backgroundColor: lineAreaColor
+                    },
+                    point: {
+                        pointBorderColor: extraLineColor,
+                        pointBackgroundColor: lineAreaColor,
+                        radius: 4,
+                        borderWidth: 1
                     }
                 }
             };
@@ -477,4 +549,37 @@ export class RemousResultsComponent extends ResultsComponentDirective implements
     public exportAsImage(element: HTMLDivElement) {
         AppComponent.exportAsImage(element.querySelector("canvas"));
     }
+
+    public resetZoom1() {
+        this.chartComponent1.chart.resetZoom();
+        this._zoom1WasChanged = false;
+    }
+
+    public resetZoom2() {
+        this.chartComponent2.chart.resetZoom();
+        this._zoom2WasChanged = false;
+    }
+
+    public zoom1Complete() {
+        this._zoom1WasChanged = true;
+        console.log("detect changes");
+        this.cd.detectChanges();
+    }
+
+    public zoom2Complete() {
+        this._zoom2WasChanged = true;
+        this.cd.detectChanges();
+    }
+
+    public get zoom1WasChanged(): boolean {
+        return this._zoom1WasChanged;
+    }
+
+    public get zoom2WasChanged(): boolean {
+        return this._zoom2WasChanged;
+    }
+
+    public get uitextResetZoomTitle() {
+        return this.intlService.localizeText("INFO_CHART_BUTTON_TITLE_RESET_ZOOM");
+    }
 }
diff --git a/src/app/components/results-chart/results-chart.component.html b/src/app/components/results-chart/results-chart.component.html
index be55ade023ec1c2b38630011af12ef652a515152..8f135402d682a7e9a088196130e0d00937ba99b9 100644
--- a/src/app/components/results-chart/results-chart.component.html
+++ b/src/app/components/results-chart/results-chart.component.html
@@ -17,8 +17,8 @@
         </div>
 
         <div *ngIf="! displayChart" class="fake-chart"></div><!-- trick to avoid blinking effect due to forceRebuild -->
-        <chart *ngIf="displayChart" [type]="graph_type" [data]="graph_data" [options]="graph_options">
-        </chart>
+        <canvas baseChart #chartcanvas="base-chart" *ngIf="displayChart" [type]="graph_type" [data]="graph_data" [options]="graph_options">
+        </canvas>
     </div>
 </div>
 
diff --git a/src/app/components/results-chart/results-chart.component.ts b/src/app/components/results-chart/results-chart.component.ts
index a547f1097474621a175fdb755fb4b9dd7c2417c1..bb0c86a0120db83f21857ae0ba97d05c204255cf 100644
--- a/src/app/components/results-chart/results-chart.component.ts
+++ b/src/app/components/results-chart/results-chart.component.ts
@@ -1,6 +1,6 @@
 import { Component, ViewChild, AfterContentInit, ChangeDetectorRef, Input, OnChanges } from "@angular/core";
 
-import { ChartComponent } from "angular2-chartjs";
+import { BaseChartDirective, NgChartsModule } from "ng2-charts";
 
 import { Observer, ParamFamily, Result } from "jalhyd";
 
@@ -14,6 +14,9 @@ import { VarResults } from "../../results/var-results";
 import { fv } from "../../util";
 import { AppComponent } from "../../app.component";
 
+import zoomPlugin from 'chartjs-plugin-zoom';
+import { Chart } from "chart.js";
+
 @Component({
     selector: "results-chart",
     templateUrl: "./results-chart.component.html",
@@ -23,8 +26,8 @@ import { AppComponent } from "../../app.component";
 })
 export class ResultsChartComponent extends ResultsComponentDirective implements AfterContentInit, Observer, OnChanges {
 
-    @ViewChild(ChartComponent)
-    private chartComponent;
+    @ViewChild('chartcanvas')
+    private chartComponent: BaseChartDirective;
 
     private _results: PlottableData;
 
@@ -47,12 +50,14 @@ export class ResultsChartComponent extends ResultsComponentDirective implements
         animation: {
             duration: 0
         },
-        legend: {
-            display: false
-        },
-        title: {
-            display: true,
-            text: ""
+        plugins: {
+            legend: {
+                display: false
+            },
+            title: {
+                display: true,
+                text: ""
+            }
         },
         elements: {
             line: {
@@ -66,17 +71,17 @@ export class ResultsChartComponent extends ResultsComponentDirective implements
         private cd: ChangeDetectorRef
     ) {
         super();
+        Chart.register(zoomPlugin);
         // enable zoom and pan (using "chartjs-plugin-zoom" package)
         const that = this;
         this.graph_options["plugins"] = {
             zoom: {
                 pan: {
                     enabled: false, // conflicts with drag zoom
-                    mode: "xy",
                 },
                 zoom: {
-                    enabled: true,
                     drag: { // conflicts with pan; set to false to enable mouse wheel zoom,
+                        enabled: true,
                         borderColor: "rgba(225,225,225,0.3)",
                         borderWidth: 1,
                         backgroundColor: "rgba(0,0,0,0.25)"
@@ -250,42 +255,42 @@ export class ResultsChartComponent extends ResultsComponentDirective implements
         }
 
         this.graph_options["scales"] = {
-            xAxes: [{
+            x: {
                 gridLines: {
                     offsetGridLines: true
                 },
                 ticks: {
                     precision: ResultsComponentDirective.CHARTS_AXIS_PRECISION,
-                    callback: function(value, index, values) {
+                    callback: function (value, index, values) {
                         return fv(Number(value));
                     }
                 },
-                scaleLabel: {
+                title: {
                     display: true,
-                    labelString: this.axisLabelWithoutSymbol(this.chartX)
+                    text: this.axisLabelWithoutSymbol(this.chartX)
                 }
-            }],
-            yAxes: [{
-                scaleLabel: {
+            },
+            y: {
+                title: {
                     display: true,
-                    labelString: this.axisLabelWithoutSymbol(this.chartY)
+                    text: this.axisLabelWithoutSymbol(this.chartY)
                 }
-            }]
+            }
         };
 
         const that = this;
-        this.graph_options["tooltips"] = {
+        this.graph_options["tooltip"] = {
             displayColors: false,
             callbacks: {
-                title: (tooltipItems, data) => {
-                    return this.chartY + " = " + fv(Number(tooltipItems[0].yLabel));
+                title: (tooltipItems) => {
+                    return this.chartY + " = " + fv(Number(tooltipItems[0].formattedValue));
                 },
-                label: (tooltipItem, data) => {
+                label: (tooltipItem) => {
                     const lines: string[] = [];
                     const nbLines = that._results.getVariatingParametersSymbols().length;
                     for (const v of that._results.getVariatingParametersSymbols()) {
                         const series = that._results.getValuesSeries(v);
-                        const line = v + " = " + fv(series[tooltipItem.index]);
+                        const line = v + " = " + fv(series[tooltipItem.dataIndex]);
                         if (v === this.chartX) {
                             if (nbLines > 1) {
                                 lines.unshift("");
@@ -347,54 +352,54 @@ export class ResultsChartComponent extends ResultsComponentDirective implements
         }
 
         this.graph_options["scales"] = {
-            xAxes: [{
+            x: {
                 type: "linear",
                 position: "bottom",
                 ticks: {
                     precision: ResultsComponentDirective.CHARTS_AXIS_PRECISION
                 },
-                scaleLabel: {
+                title: {
                     display: true,
-                    labelString: this.axisLabelWithoutSymbol(this.chartX)
+                    text: this.axisLabelWithoutSymbol(this.chartX)
                 }
-            }],
-            yAxes: [{
+            },
+            y: {
                 type: "linear",
                 position: "left",
                 ticks: {
                     precision: ResultsComponentDirective.CHARTS_AXIS_PRECISION
                 },
-                scaleLabel: {
+                title: {
                     display: true,
-                    labelString: this.axisLabelWithoutSymbol(this.chartY)
+                    text: this.axisLabelWithoutSymbol(this.chartY)
                 }
-            }]
+            }
         };
 
         if (isMultiple) {
             // add legend for multiple series
-            this.graph_options.legend = {
+            this.graph_options.plugins.legend = {
                 display: true,
                 position: "bottom",
                 reverse: false
             };
-            // remove tooltips
-            delete this.graph_options.tooltips;
+            // remove tooltip
+            delete this.graph_options.tooltip;
         } else {
-            // enhanced tooltips for single series
+            // enhanced tooltip for single series
             const that = this;
-            this.graph_options.tooltips = {
+            this.graph_options.tooltip = {
                 displayColors: false,
                 callbacks: {
-                    title: (tooltipItems, data) => {
-                        return this.chartY + " = " + fv(Number(tooltipItems[0].yLabel));
+                    title: (tooltipItems) => {
+                        return this.chartY + " = " + fv(Number(tooltipItems[0].formattedValue));
                     },
-                    label: (tooltipItem, data) => {
+                    label: (tooltipItem) => {
                         let lines: string[] = [];
                         // 1. X if different from Y
                         if (this.chartX !== this.chartY) {
                             const xseries = that._results.getValuesSeries(this.chartX);
-                            const xline = this.chartX + " = " + fv(xseries[tooltipItem.index]);
+                            const xline = this.chartX + " = " + fv(xseries[tooltipItem.dataIndex]);
                             lines.push(xline);
                         }
                         // 2. variated parameters other than X or Y
@@ -402,7 +407,7 @@ export class ResultsChartComponent extends ResultsComponentDirective implements
                         for (const v of that._results.getVariatingParametersSymbols()) {
                             if (v !== this.chartX && v !== this.chartY) {
                                 const series = that._results.getValuesSeries(v);
-                                const line = v + " = " + fv(series[tooltipItem.index]);
+                                const line = v + " = " + fv(series[tooltipItem.dataIndex]);
                                 varLines.push(line);
                             }
                         }
@@ -416,7 +421,7 @@ export class ResultsChartComponent extends ResultsComponentDirective implements
                 }
             };
             // remove legend
-            this.graph_options.legend = {
+            this.graph_options.plugins.legend = {
                 display: false
             };
         }
diff --git a/src/app/formulaire/definition/form-courbe-remous.ts b/src/app/formulaire/definition/form-courbe-remous.ts
index 304fef0ba260451543d63aea3d0a314bbe2efc6d..3762c846cb3fd3c5a11a21d850746f0a024c9074 100644
--- a/src/app/formulaire/definition/form-courbe-remous.ts
+++ b/src/app/formulaire/definition/form-courbe-remous.ts
@@ -16,6 +16,7 @@ export class FormulaireCourbeRemous extends FormulaireSection {
     constructor() {
         super();
         this._remousResults = new RemousResults(this);
+        this.updateCalcResults();
         this._props["varCalc"] = ""; // important
     }
 
@@ -27,43 +28,44 @@ export class FormulaireCourbeRemous extends FormulaireSection {
         const cr: CourbeRemous = this.currentNub as CourbeRemous;
         const prmCR: CourbeRemousParams = cr.prms as CourbeRemousParams;
 
-        this.remousResults.parameters = prmCR;
+        this._remousResults.parameters = prmCR;
 
         // variable supplémentaire à calculer
-        this.remousResults.extraParamSymbol = this.currentNub.properties.getPropValue("varCalc");
+        this._remousResults.extraParamSymbol = this.currentNub.properties.getPropValue("varCalc");
 
         // calcul
-        this.remousResults.result = cr.CalcSerie();
+        this._remousResults.result = cr.CalcSerie();
 
         const sect: acSection = cr.Sn;
         this.resultYn = sect.CalcSection("Yn"); // hauteur normale
         this.resultYc = sect.CalcSection("Yc"); // hauteur critique
 
         // données du graphique
-        this.remousResults.hauteurNormale = this.resultYn.resultElement;
-        this.remousResults.hauteurCritique = this.resultYc.resultElement;
-        if (this.remousResults.extraParamSymbol) {
-            this.remousResults.extraChart = ! ["Hs", "Hsc", "Ycor", "Ycon"].includes(this.remousResults.extraParamSymbol);
+        this._remousResults.hauteurNormale = this.resultYn.resultElement;
+        this._remousResults.hauteurCritique = this.resultYc.resultElement;
+        if (this._remousResults.extraParamSymbol) {
+            this._remousResults.extraChart = !["Hs", "Hsc", "Ycor", "Ycon"].includes(this._remousResults.extraParamSymbol);
         } else {
-            this.remousResults.extraChart = false;
+            this._remousResults.extraChart = false;
         }
+        this.updateCalcResults();
     }
 
-    public get remousResults() {
-        return this._remousResults;
+    protected updateCalcResults() {
+        this._calcResults = [];
+        if (this._remousResults) {
+            // ensure help links are propagated
+            this._remousResults.helpLinks = this.helpLinks;
+            this._calcResults.push(this._remousResults);
+        }
     }
 
     public resetFormResults() {
         this._remousResults.reset();
+        this.updateCalcResults();
     }
 
     public get hasResults(): boolean {
         return this._remousResults.hasResults;
     }
-
-    public get results(): CalculatorResults[] {
-        // ensure help links are propagated
-        this._remousResults.helpLinks = this.helpLinks;
-        return [ this._remousResults ];
-    }
 }
diff --git a/src/app/formulaire/definition/form-definition.ts b/src/app/formulaire/definition/form-definition.ts
index 3fd3ee3a274ab1fedb90e0ae8b2c166701210aea..bacf4f4d1ee97117db288b0ac8188008fc68b6ca 100644
--- a/src/app/formulaire/definition/form-definition.ts
+++ b/src/app/formulaire/definition/form-definition.ts
@@ -56,6 +56,15 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs
     /** copy of options.resultsHelp read by FormDefinition.parseOptions() */
     public helpLinks: { [key: string]: string };
 
+    /*
+    * Propriété destinée à éviter des MAJ intempestives par Angular : avant, le getter public get results()
+    * recréait à chaque appel un tableau CalculatorResults[], ce qui était détecté par Angular
+    * comme un changement même si les résultats stockés dans le tableau n'étaient pas modifiés.
+    *  A présent, _calcResults n'est recréé que si les resultats sont modifiés
+    *  (cf. updateCalcResults()).
+    */
+    protected _calcResults: CalculatorResults[];
+
     constructor(parent?: FormulaireNode) {
         super(parent);
     }
@@ -435,12 +444,23 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs
 
     public abstract get hasResults(): boolean;
 
-    public abstract get results(): CalculatorResults[];
+    public get results(): CalculatorResults[] {
+        return this._calcResults;
+    }
+
+    /**
+     * Recrée l'objet retourné par public get results() et
+     * évite des mises à jour par Angular dues à un une détection
+     * de changement causée par le fait que get results() recréait
+     * systématiquement un CalculatorResults[]
+     */
+    protected abstract updateCalcResults();
 
     /**
      * Copies current Nub result into result components for display on page.
      * Should be called every time the Nub result changes.
      * Must be idempotent.
+     * Must call updateCalcResults() at the end.
      */
     protected abstract reaffectResultComponents();
 
diff --git a/src/app/formulaire/definition/form-fixedvar.ts b/src/app/formulaire/definition/form-fixedvar.ts
index 7b596ffbf07e355a534a3298fc67bdb6a641b07c..575f7cb100cff6c9f2a3061ce3c27f2812f9e747 100644
--- a/src/app/formulaire/definition/form-fixedvar.ts
+++ b/src/app/formulaire/definition/form-fixedvar.ts
@@ -25,16 +25,13 @@ export class FormulaireFixedVar extends FormulaireDefinition {
         super(parent);
         this._fixedResults = new FixedResults();
         this._varResults = new VarResults(this);
+        this.updateCalcResults();
     }
 
     public get fixedResults() {
         return this._fixedResults;
     }
 
-    public get varResults() {
-        return this._varResults;
-    }
-
     public get selectids(): string[] {
         return this._selectIds;
     }
@@ -42,9 +39,10 @@ export class FormulaireFixedVar extends FormulaireDefinition {
     public resetFormResults() {
         this._fixedResults.reset();
         this._varResults.reset();
+        this.updateCalcResults();
     }
 
-    public addFixedParameters() {
+    protected addFixedParameters() {
         for (const p of this.getFixedParameters()) {
             this._fixedResults.addFixedParameter(p);
         }
@@ -52,20 +50,26 @@ export class FormulaireFixedVar extends FormulaireDefinition {
 
     public set chartType(t: ChartType) {
         this._varResults.chartType = t;
+        this.updateCalcResults();
     }
 
     public get hasResults(): boolean {
         return this._fixedResults.hasResults || this._varResults.hasResults;
     }
 
-    public get results(): CalculatorResults[] {
-        const res: CalculatorResults[] = [];
+    /**
+     * Recrée l'objet retourné par public get results() et
+     * évite des mises à jour par Angular dues à un une détection
+     * de changement causée par le fait que get results() recréait
+     * systématiquement un CalculatorResults[]
+     */
+    protected updateCalcResults() {
+        this._calcResults = [];
         // ensure help links are propagated
         this._fixedResults.helpLinks = this.helpLinks;
         this._varResults.helpLinks = this.helpLinks;
-        res.push(this._fixedResults);
-        res.push(this._varResults);
-        return res;
+        this._calcResults.push(this._fixedResults);
+        this._calcResults.push(this._varResults);
     }
 
     public afterParseFieldset(fs: FieldSet) {
@@ -120,20 +124,21 @@ export class FormulaireFixedVar extends FormulaireDefinition {
 
         if (varParams.length === 0) {
             // pas de paramètre à varier
-            this.fixedResults.result = nub.result;
+            this._fixedResults.result = nub.result;
             if (computedParam !== undefined) {
-                this.fixedResults.calculatedParameter = computedParam;
+                this._fixedResults.calculatedParameter = computedParam;
             }
         } else {
             // il y a un paramètre à varier
-            this.varResults.variatedParameters = varParams;
+            this._varResults.variatedParameters = varParams;
             if (computedParam !== undefined) {
-                this.varResults.calculatedParameter = computedParam;
+                this._varResults.calculatedParameter = computedParam;
             }
 
-            this.varResults.result = nub.result;
-            this.varResults.update();
+            this._varResults.result = nub.result;
+            this._varResults.update();
         }
+        this.updateCalcResults();
     }
 
     /**
diff --git a/src/app/formulaire/definition/form-macrorugo-compound.ts b/src/app/formulaire/definition/form-macrorugo-compound.ts
index a8cbc7ac605ee477cc3a4bbdfa10e6744b7bdf18..b28b59b7d21e335b8605e9d7b84ce1851eb4836d 100644
--- a/src/app/formulaire/definition/form-macrorugo-compound.ts
+++ b/src/app/formulaire/definition/form-macrorugo-compound.ts
@@ -18,6 +18,7 @@ export class FormulaireMacrorugoCompound extends FormulaireRepeatableFieldset {
     constructor() {
         super();
         this._mrcResults = new MacrorugoCompoundResults();
+        this.updateCalcResults();
         // default properties
         this._props["inclinedApron"] = MRCInclination.NOT_INCLINED;
     }
@@ -119,18 +120,18 @@ export class FormulaireMacrorugoCompound extends FormulaireRepeatableFieldset {
         const varParams: VariatedDetails[] = this.getVariatedParameters();
 
         // résultat de calcul de la passe à macrorugo complexe
-        const mrcr = this.mrcResults;
-        mrcr.calculatedParameter = computedParam;
-        mrcr.result = mrc.result;
+        this._mrcResults.calculatedParameter = computedParam;
+        this._mrcResults.result = mrc.result;
         if (varParams) {
-            mrcr.variatedParameters = varParams;
+            this._mrcResults.variatedParameters = varParams;
         }
         // résultat de chaque enfant
         const cr: Result[] = [];
         for (const c of mrc.children) {
             cr.push(c.result);
         }
-        mrcr.childrenResults = cr;
+        this._mrcResults.childrenResults = cr;
+        this.updateCalcResults();
     }
 
     public get mrcResults() {
@@ -139,12 +140,16 @@ export class FormulaireMacrorugoCompound extends FormulaireRepeatableFieldset {
 
     public resetFormResults() {
         this._mrcResults.reset();
+        this.updateCalcResults();
     }
 
-    public get results(): CalculatorResults[] {
-        // ensure help links are propagated
-        this._mrcResults.helpLinks = this.helpLinks;
-        return [ this._mrcResults ];
+    protected updateCalcResults() {
+        this._calcResults = [];
+        if (this._mrcResults) {
+            // ensure help links are propagated
+            this._mrcResults.helpLinks = this.helpLinks;
+            this._calcResults.push(this._mrcResults);
+        }
     }
 
     public get hasResults(): boolean {
diff --git a/src/app/formulaire/definition/form-pab.ts b/src/app/formulaire/definition/form-pab.ts
index af9b7f56d9ea67134a0d682678477961df20f646..b82eea4549cd409a9587cfaaad52f0acc9badc96 100644
--- a/src/app/formulaire/definition/form-pab.ts
+++ b/src/app/formulaire/definition/form-pab.ts
@@ -17,6 +17,7 @@ export class FormulairePab extends FormulaireDefinition {
     constructor() {
         super();
         this._pabResults = new PabResults();
+        this.updateCalcResults();
     }
 
     public get pabNub(): Pab {
@@ -38,21 +39,20 @@ export class FormulairePab extends FormulaireDefinition {
         const varParams: VariatedDetails[] = this.getVariatedParameters();
 
         // résultat de calcul de la passe à bassins
-        const pabr = this.pabResults;
-        pabr.calculatedParameter = computedParam;
-        pabr.result = pab.result;
+        this._pabResults.calculatedParameter = computedParam;
+        this._pabResults.result = pab.result;
 
         // résultat de chaque cloison
         const cr: Result[] = [];
         for (const c of pab.children) {
             cr.push(c.result);
         }
-        pabr.cloisonsResults = cr;
+        this._pabResults.cloisonsResults = cr;
         // résultat de la cloison aval
-        pabr.cloisonAvalResults = pab.downWall.result;
+        this._pabResults.cloisonAvalResults = pab.downWall.result;
 
         // cote aval de la passe
-        pabr.Z2 = [];
+        this._pabResults.Z2 = [];
         if (varParams.length > 0) {
             // find longest list
             const lvp = longestVarParam(varParams);
@@ -62,20 +62,22 @@ export class FormulairePab extends FormulaireDefinition {
                 const iter = pab.prms.Z2.getExtendedValuesIterator(longest);
                 while (iter.hasNext) {
                     const nv = iter.next();
-                    pabr.Z2.push(nv.value);
+                    this._pabResults.Z2.push(nv.value);
                 }
             } else {
                 for (let i = 0; i < longest; i++) {
-                    pabr.Z2.push(pab.prms.Z2.v);
+                    this._pabResults.Z2.push(pab.prms.Z2.v);
                 }
             }
         } else {
-            pabr.Z2 = [ pab.prms.Z2.singleValue ];
+            this._pabResults.Z2 = [pab.prms.Z2.singleValue];
         }
 
         if (varParams) {
-            pabr.variatedParameters = varParams;
+            this._pabResults.variatedParameters = varParams;
         }
+
+        this.updateCalcResults();
     }
 
     public get pabResults() {
@@ -84,12 +86,16 @@ export class FormulairePab extends FormulaireDefinition {
 
     public resetFormResults() {
         this._pabResults.reset();
+        this.updateCalcResults();
     }
 
-    public get results(): CalculatorResults[] {
-        // ensure help links are propagated
-        this._pabResults.helpLinks = this.helpLinks;
-        return [ this._pabResults ];
+    protected updateCalcResults() {
+        this._calcResults = [];
+        if (this._pabResults) {
+            // ensure help links are propagated
+            this._pabResults.helpLinks = this.helpLinks;
+            this._calcResults.push(this._pabResults);
+        }
     }
 
     public get hasResults(): boolean {
diff --git a/src/app/formulaire/definition/form-prebarrage.ts b/src/app/formulaire/definition/form-prebarrage.ts
index 993a72e8b5fe00c3daf93888ba338a5fa12c73e2..8f317caba59b6b5218a157daccf1b6cc6ffd2884 100644
--- a/src/app/formulaire/definition/form-prebarrage.ts
+++ b/src/app/formulaire/definition/form-prebarrage.ts
@@ -42,6 +42,7 @@ export class FormulairePrebarrage extends FormulaireFixedVar {
     constructor() {
         super();
         this._pbResults = new PrebarrageResults();
+        this.updateCalcResults();
         this._pbResults.addObserver(this);
     }
 
@@ -53,10 +54,13 @@ export class FormulairePrebarrage extends FormulaireFixedVar {
         return this._pbResults;
     }
 
-    public get results(): CalculatorResults[] {
-        // ensure help links are propagated
-        this._pbResults.helpLinks = this.helpLinks;
-        return [this._pbResults];
+    protected updateCalcResults() {
+        this._calcResults = [];
+        if (this._pbResults) {
+            // ensure help links are propagated
+            this._pbResults.helpLinks = this.helpLinks;
+            this._calcResults.push(this._pbResults);
+        }
     }
 
     public get hasResults(): boolean {
@@ -219,8 +223,7 @@ export class FormulairePrebarrage extends FormulaireFixedVar {
         this.runNubCalc(this.currentNub);
         this.refreshFieldsets(); // important: before reaffectResultComponents() or it will break results components localization
         // reset variable index to avoid trying to access an index > 0 when nothing varies
-        const pbr = this.pbResults;
-        pbr.variableIndex = 0;
+        this._pbResults.variableIndex = 0;
 
         this.reaffectResultComponents();
         this.refreshSchema();
@@ -231,39 +234,41 @@ export class FormulairePrebarrage extends FormulaireFixedVar {
         const computedParam: NgParameter = this.getComputedParameter();
 
         // cacher les résultats
-        this.pbResults.reset();
+        this._pbResults.reset();
         this.addFixedParameters();
 
         // pour le sélecteur d'itérations
         const varParams: VariatedDetails[] = this.getVariatedParameters();
         if (varParams) {
-            this.pbResults.variatedParameters = varParams;
+            this._pbResults.variatedParameters = varParams;
             const lvp = longestVarParam(this._pbResults.variatedParameters);
             this._pbResults.size = lvp.size;
             this._pbResults.cloisonResults.size = lvp.size;
         }
 
-        this.pbResults.result = pb.result;
+        this._pbResults.result = pb.result;
         // résultats selon l'objet sélectionné sur le schéma
         if (this._selectedItem !== undefined && this._selectedItem instanceof PbCloison) {
             // afficher les résultats de cloison
-            this.pbResults.cloisonResults.result = this._selectedItem.result;
+            this._pbResults.cloisonResults.result = this._selectedItem.result;
             if (computedParam !== undefined) {
-                this.pbResults.cloisonResults.calculatedParameter = computedParam;
+                this._pbResults.cloisonResults.calculatedParameter = computedParam;
             }
             // transmission des suffixes de cloisons calculés par l'algo de tri de PbSchemaComponent,
             // pour le sélecteur de conditions limites
             const pbs = this.kids[0] as PbSchema;
-            this.pbResults.wallsSuffixes = pbs.wallsSuffixes;
+            this._pbResults.wallsSuffixes = pbs.wallsSuffixes;
         } else {
             // afficher les résultats des bassins
             // résultat général du Nub (amont, aval, débit)
-            this.pbResults.calculatedParameter = computedParam;
+            this._pbResults.calculatedParameter = computedParam;
             // résultat de chaque bassin
             for (const b of pb.bassins) {
-                this.pbResults.bassinsResults.push(b.result);
+                this._pbResults.bassinsResults.push(b.result);
             }
         }
+
+        this.updateCalcResults();
     }
 
     /**
@@ -282,7 +287,7 @@ export class FormulairePrebarrage extends FormulaireFixedVar {
         }
     }
 
-    public addFixedParameters() {
+    protected addFixedParameters() {
         if (this._selectedItem !== undefined && this._selectedItem instanceof PbCloison) {
             for (const s of this._selectedItem.structures) {
                 for (const p of s.parameterIterator) {
@@ -300,6 +305,7 @@ export class FormulairePrebarrage extends FormulaireFixedVar {
 
     public resetFormResults() {
         this._pbResults.reset();
+        this.updateCalcResults();
     }
 
     public resetResults() {
diff --git a/src/app/formulaire/definition/form-section-parametree.ts b/src/app/formulaire/definition/form-section-parametree.ts
index 743880b5da19f5ae0542af1402223df2537a29db..7f91f2fca963c76ba3e5bae49cfa8adc511afa8b 100644
--- a/src/app/formulaire/definition/form-section-parametree.ts
+++ b/src/app/formulaire/definition/form-section-parametree.ts
@@ -15,6 +15,7 @@ export class FormulaireSectionParametree extends FormulaireSection {
     public constructor() {
         super();
         this._sectionResults = new SectionResults();
+        this.updateCalcResults();
     }
 
     protected compute() {
@@ -43,15 +44,16 @@ export class FormulaireSectionParametree extends FormulaireSection {
             this._sectionResults.result = sectNub.result;
             // résultats complémentaires des paramètres fixés
             this.addFixedParameters();
-            this.fixedResults.result = sectNub.result;
+            this._fixedResults.result = sectNub.result;
         }
-
+        this.updateCalcResults();
     }
 
     public resetFormResults() {
         this._fixedResults.reset();
         this._varResults.reset();
         this._sectionResults.reset();
+        this.updateCalcResults();
     }
 
     public get hasResults(): boolean {
@@ -60,15 +62,16 @@ export class FormulaireSectionParametree extends FormulaireSection {
             || (this._sectionResults?.hasResults);
     }
 
-    public get results(): CalculatorResults[] {
-        const res: CalculatorResults[] = [];
+    protected updateCalcResults() {
+        this._calcResults = [];
         // ensure help links are propagated
         this._fixedResults.helpLinks = this.helpLinks;
         this._varResults.helpLinks = this.helpLinks;
-        this._sectionResults.helpLinks = this.helpLinks;
-        res.push(this._fixedResults);
-        res.push(this._varResults);
-        res.push(this._sectionResults);
-        return res;
+        this._calcResults.push(this._fixedResults);
+        this._calcResults.push(this._varResults);
+        if(this._sectionResults){
+            this._sectionResults.helpLinks = this.helpLinks;
+            this._calcResults.push(this._sectionResults);
+        }
     }
 }
diff --git a/src/app/formulaire/definition/form-verificateur.ts b/src/app/formulaire/definition/form-verificateur.ts
index b357c4a0de658da92bac30bb62669bdd13caeb67..3bcd463a65b77779aea4aa3ba7875ddae91adcac 100644
--- a/src/app/formulaire/definition/form-verificateur.ts
+++ b/src/app/formulaire/definition/form-verificateur.ts
@@ -16,6 +16,7 @@ export class FormulaireVerificateur extends FormulaireFixedVar {
     constructor() {
         super();
         this._verificateurResults = new VerificateurResults();
+        this.updateCalcResults();
     }
 
     public get verificateurNub(): Verificateur {
@@ -59,14 +60,17 @@ export class FormulaireVerificateur extends FormulaireFixedVar {
             er.push(sp.result);
         }
         vr.especeResults = er;
-    }
 
+        this.updateCalcResults();
+    }
+    
     public resetFormResults() {
         this._verificateurResults.reset();
+        this.updateCalcResults();
     }
 
-    public get results(): CalculatorResults[] {
-        return [ this._verificateurResults ];
+    protected updateCalcResults() {
+        this._calcResults = [this._verificateurResults];
     }
 
     public get hasResults(): boolean {