diff --git a/src/app/components/modules-diagram/modules-diagram.component.html b/src/app/components/modules-diagram/modules-diagram.component.html
index 35e34960e18fad5f8ee4526587cfaf31573c8efc..4eaa708ce1c090aca6daf7119949b86c3855bfd6 100644
--- a/src/app/components/modules-diagram/modules-diagram.component.html
+++ b/src/app/components/modules-diagram/modules-diagram.component.html
@@ -12,9 +12,10 @@
 
         <div id="diagram" #diagram></div>
 
-        <a class="show-debug" (click)="initSvgPanZoom()">init zoom </a>
+        <!-- <a class="show-debug" (click)="initSvgPanZoom()">init zoom </a> -->
+
+        <!-- <a class="show-debug" (click)="showDebug = ! showDebug"> debug</a> -->
 
-        <a class="show-debug" (click)="showDebug = ! showDebug"> debug</a>
         <div *ngIf="showDebug">
             <pre>{{ graphDef }}</pre>
         </div>
diff --git a/src/app/components/modules-diagram/modules-diagram.component.ts b/src/app/components/modules-diagram/modules-diagram.component.ts
index 4b14480c3f3d9d325ade88b378d92b4e1c58d677..f9675ef8507df69c1a0adb26226d3b0da8e38b2a 100644
--- a/src/app/components/modules-diagram/modules-diagram.component.ts
+++ b/src/app/components/modules-diagram/modules-diagram.component.ts
@@ -3,14 +3,22 @@ import {
     ViewChild,
     AfterContentInit,
     OnInit,
-    AfterViewChecked
+    AfterViewChecked,
+    AfterViewInit
 } from "@angular/core";
 import { Router } from "@angular/router";
 
+import {
+    Session,
+    ParamValueMode,
+    CalculatorType,
+    ComputeNodeType,
+    LoiDebit,
+    Nub
+} from "jalhyd";
+
 import { I18nService } from "../../services/internationalisation/internationalisation.service";
 import { BaseComponent } from "../base/base.component";
-
-import { Session, ParamValueMode } from "jalhyd";
 import { FormulaireService } from "../../services/formulaire/formulaire.service";
 
 import * as mermaid from "mermaid";
@@ -22,13 +30,14 @@ import * as SvgPanZoom from "svg-pan-zoom";
     templateUrl: "./modules-diagram.component.html",
     styleUrls: ["./modules-diagram.component.scss"]
 })
-export class ModulesDiagramComponent extends BaseComponent implements AfterContentInit, AfterViewChecked, OnInit {
+export class ModulesDiagramComponent extends BaseComponent implements AfterContentInit, AfterViewChecked, AfterViewInit, OnInit {
 
     private svgPanZoom: SvgPanZoom.Instance = null;
 
     private needsToInitSvgPanZoom = false;
 
-    // private readonly externalFunctionName: string = "functionToCallIntoAngular";
+    /** handle on SVG container */
+    private nativeElement: any;
 
     @ViewChild("diagram", { static: true })
     public diagram;
@@ -40,32 +49,12 @@ export class ModulesDiagramComponent extends BaseComponent implements AfterConte
     constructor(
         private intlService: I18nService,
         private router: Router,
-        private formulaireService: FormulaireService/* ,
-        zone: NgZone */
+        private formulaireService: FormulaireService
     ) {
         super();
         this.error = false;
-        // create a new global variable in the page
-        // window[this.externalFunctionName] = this.buildPublicCall(zone, this);
     }
 
-    /* ngOnDestroy() {
-        window[this.externalFunctionName] = null;
-    } */
-
-    // generate a function that has the zone and "this"
-    // captured in a closure.
-    /* private buildPublicCall(zone: NgZone, diagramComponent: ModulesDiagramComponent): any {
-        return function angularAppGlobalMethod( nodeId ) {
-            // you can't call "this.increment( nodeId)" because
-            // when the code is run on a click, "this" won't be
-            // the right entity. When the function is constructed
-            // "this" is the right entity, but it needs to captured
-            // at the point of construction
-            zone.run(() => { diagramComponent.openCalc( nodeId ); });
-        };
-    } */
-
     public get uitextTitle(): string {
         return this.intlService.localizeText("INFO_DIAGRAM_TITLE");
     }
@@ -100,16 +89,28 @@ export class ModulesDiagramComponent extends BaseComponent implements AfterConte
         }
     }
 
+    public ngAfterViewInit(): void {
+        // add click listener on every calculator node in the graph, that
+        // corresponds to an open module
+        this.nativeElement.querySelectorAll("g.node").forEach(item => {
+            if (item.id && this.formIsOpen(item.id)) {
+                item.style.cursor = "pointer";
+                item.addEventListener("click", () => {
+                    this.openCalc(item.id);
+                });
+            }
+        });
+    }
+
     public ngAfterContentInit(): void {
         this.error = false;
         mermaid.initialize({
             // theme: "forest", // @TODO thème Irstea !
-            securityLevel: false, // or "loose" ?
             flowchart: {
-                curve: "basis" // default: "linear"
+                curve: "basis"
             }
         });
-        const element: any = this.diagram.nativeElement;
+        this.nativeElement = this.diagram.nativeElement;
 
         if (this.hasModules) {
             // generate graph description
@@ -117,7 +118,7 @@ export class ModulesDiagramComponent extends BaseComponent implements AfterConte
             // draw
             try {
                 mermaid.render("graphDiv", graphDefinition, (svgCode, bindFunctions) => {
-                    element.innerHTML = svgCode;
+                    this.nativeElement.innerHTML = svgCode;
                 });
             } catch (e) {
                 console.error(e);
@@ -154,14 +155,13 @@ export class ModulesDiagramComponent extends BaseComponent implements AfterConte
                 def.push("subgraph \"" + f.calculatorName + "\"");
                 def.push(f.uid + "(\"" + f.calculatorName + "\")");
                 for (const c of children) {
-                    def.push(c.uid + "[\"" + c.constructor.name + "\"]");
+                    def.push(c.uid + "[\"" + this.describe(c) + "\"]");
                     def.push(f.uid + " --- " + c.uid);
                 }
                 def.push("end");
             } else {
                 // simple Nub (no children)
                 def.push(f.uid + "(\"" + f.calculatorName + "\")");
-                def.push("click " + f.uid + " openCalc \"open module\"");
             }
             // fnid all linked parameters
             for (const p of nub.parameterIterator) {
@@ -184,6 +184,37 @@ export class ModulesDiagramComponent extends BaseComponent implements AfterConte
     }
 
     public openCalc(uid: string) {
-        console.log("Opening calc", uid);
+        this.router.navigate(["/calculator", uid]);
+    }
+
+    /**
+     * Returns a very short "description" of the given Nub,
+     * based on the most specific of its properties
+     */
+    private describe(n: Nub) {
+        let type = CalculatorType[n.calcType];
+        const nt = n.properties.getPropValue("nodeType");
+        if (nt) {
+            type = ComputeNodeType[nt];
+        } else {
+            const ld = n.properties.getPropValue("loiDebit");
+            if (ld !== undefined) {
+                type = LoiDebit[ld];
+            }
+        }
+        return type;
+    }
+
+    /**
+     * Returns true if uid is the id of the main Nub of any
+     * of the open modules
+     */
+    private formIsOpen(uid: string) {
+        for (const f of this.formulaireService.formulaires) {
+            if (f.currentNub.uid === uid) {
+                return true;
+            }
+        }
+        return false;
     }
 }