• Rendu en HTML

  • Rendu en PDF

  • Rendu en Mails

  • Rendu en CSV

Le Diagram DSL permet de dessiner rapidement des diagrammes en barres (bar), en aires (area), en secteurs (pie), en nuage de points (scatter), en lignes (line), en boîtes à moustaches (whiskers) et en chronologie (timeline), éventuellement combinés (mixed), soit rastérisés au format PNG, soit au format SVG.

Dans un bloc, un diagramme est ajouté via diagram, qui prend soit un UiDiagramSpecifier, soit une MethodClosure en retournant un, ou via diagramFilter pour l’associer à un filtre.

Exemples de graphiques

Barres (Bar)

Example 1. Diagramme en barres
Exemple de code de diagramme en barres
private static UiDiagramSpecifier barDiagram(boolean isStacked) {
    new UiDiagramSpecifier().ui {
        bar(isStacked, {
            labels "T1", "T2", "T3", "T4"
            dataset 'Truc1', 1.0, 2.0, 1.0, 4.0
            dataset 'Truc2', 2.0, 0.1, 1.0, 0.0
            dataset 'Truc3', 2.0, 0.1, 1.0, 1.0
        })
    }
}
Résultat

diag dsl bar

Lignes (Line)

Example 2. Diagramme en lignes
Exemple de code de diagramme en lignes
diagram new UiDiagramSpecifier().ui({
    line {
        labels 1.5, 3, 4.4, 5, 7.8, 8
        dataset "client", 10.0, 20.1, 30.0
        dataset "admin", 5.0, 7.0
        dataset "other", 1.0, 2.0, 3.0, 4.0, 5.0, 6.0
    }
})
Résultat

diag dsl line

Secteurs (Pie)

Example 3. Diagramme circulaire (camembert)
Exemple de code de diagramme circulaire
private static UiDiagramSpecifier pieDiagram(boolean hasSlice) {
    new UiDiagramSpecifier().ui({
        pie(hasSlice, {
            labels "Pie"
            dataset("cli", 1.47)
            dataset("client", 0.28)
            dataset("client1", 0.1)
            dataset("client2", 1.45)
            dataset("client3", 0.05)
            dataset("client31", 0.05)
            dataset("client32", 0.05)
            dataset("c33", 0.05)
            dataset("client311", 0.05)
            dataset("client312", 0.05)
            dataset("client313", 0.05)
            dataset("client4", 0.8)
            dataset("client5", 2.1)
            dataset("client55", 0.1)
            dataset("client555", 0.2)
            dataset("client5555", 0.3)
            dataset("client55555", 0.3)
            dataset("admin", 1.6)
            dataset("test1", 0.05)
        })
    })
}
Résultat

diag dsl pie

Boîtes à moustaches (Whiskers)

Example 4. Diagramme en boîtes à moustaches
Exemple de code de boîtes à moustaches
diagram new UiDiagramSpecifier().ui({
    whiskers {
        labels "T1", "T2", "T3", "T4"

        dataset 'Truc1', {
            boxData 1.0, 2.0, 3.0, 3.5, 4.0, 4.5, 5.0
            boxData 1.5, 2.5, 3.5, 6.0, 7.0, 8.0, 9.0
            boxData 2.0, 2.0, 2.1, 2.5, 5.5, 5.6, 6.7
            boxData 1.7, 1.8, 1.9, 2.0, 2.1, 2.2, 2.3
        }
        dataset 'Truc2', {
            boxData 0.5, 1.0, 1.1, 1.2, 1.3, 2.0, 5.5
            boxData 0.5, 1.0, 1.1, 1.2, 1.3, 2.0, 5.5
            boxData 0.5, 1.0, 1.1, 1.2, 1.3, 2.0, 5.5
            boxData 0.5, 1.0, 1.1, 1.2, 1.3, 2.0, 5.5
        }
    }
})
Résultat

diag dsl whiskers

Chronologie (Timeline)

Example 5. Diagramme chronologique
Exemple de code de chronologie
diagram new UiDiagramSpecifier().ui({
    timeline {
        SimpleDateFormat format = new SimpleDateFormat('yyyy-MM-dd')
        dataset 'Truc1', {
            periodData format.parse('2025-06-12'), format.parse('2025-07-08'), "Period1"
            periodData format.parse('2025-07-08'), format.parse('2025-07-21'), "Period2"
            periodData format.parse('2025-07-21'), format.parse('2025-08-30'), "Period3"
        }
        dataset 'Truc2', {
            periodData format.parse('2025-06-20'), format.parse('2025-06-25'), "Period1"
            periodData format.parse('2025-07-01'), format.parse('2025-07-21'), "Period2"
        }
    }
})
Résultat

diag dsl timeline

Combiné (Mixed)

D’autres types de diagrammes peuvent être imbriqués dans la closure d’un diagramme. Ils partagent les étiquettes de l’axe X et la légende, chaque type imbriqué possédant son propre axe Y, coloré comme ses séries de données (dataset).

Example 6. Diagramme combiné
Exemple de code de diagramme combiné
diagram new UiDiagramSpecifier().ui {
    bar {                                                           (1)
        labels 'W1', 'W2', 'W3', 'W4', 'W5', 'W6', 'W7', 'W8'
        dataset 'Line A', 55.0, 62.0, 58.0, 70.0, 74.0, 61.0, 80.0, 77.0
        dataset 'Line B', 40.0, 48.0, 44.0, 58.0, 61.0, 57.0, 70.0, 65.0
        line {                                                      (2)
            dataset 'Scrap rate (%)', 2.1, 1.8, 2.5, 1.6, 1.4, 2.9, 1.2, 1.5
        }
        scatter {                                                   (3)
            dataset 'Downtime (h)', 4.0, 6.0, 3.0, 8.0, 5.0, 2.0, 7.0, 4.0
        }
        option DiagramOption.builder
                .setTitle('Weekly production')
                .build()
    }
}
1 Diagramme principal définissant les étiquettes sur l’axe X (ici un diagramme en barres empilées)
2 Ligne imbriquée, tracée par-dessus les barres avec son propre axe Y à droite
3 Nuage de points imbriqué, avec son propre axe Y à gauche
Résultat

diag dsl mixed

Options personnalisées

Diverses options permettent de personnaliser le graphique à l’aide de DiagramOption.

Diagramme en barres utilisant DiagramOption
private static UiDiagramSpecifier barDiagram(boolean isStacked) {
    new UiDiagramSpecifier().ui {
        bar(isStacked, {
            labels "T1", "T2", "T3", "T4"
            dataset 'Truc1', 1.0, 2.0, 1.0, 4.0
            dataset 'Truc2', 2.0, 0.1, 1.0, 0.0
            dataset 'Truc3', 2.0, 0.1, 1.0, 1.0

            option DiagramOption.builder
                    .setTitle("This is a Bar chart !")
                    .hideLegend()
                    .showDataCount()
                    .setKeyColors(Color.RED, Color.ORANGE, Color.YELLOW, Color.GREEN)
                    .setClickAction(Pr2Controller.&onclickBar as MethodClosure)
                    .setResolution(DiagramResolution.DEFAULT_2K)
                    .build()
        })
    }
}
Résultat

diag dsl bar option

Options disponibles :

  • setTitle : titre du diagramme

  • hideLegend : les légendes sont affichées par défaut

  • showDataCount : affiche les valeurs sur le diagramme (masquées par défaut)

  • setKeyColors : couleurs de chaque série de données (7 couleurs par défaut)

  • setClickAction : action appelée lors d’un clic sur une forme ; elle reçoit les paramètres key (nom du dataset), x et y, en plus de l’identifiant et des paramètres fournis (voir Diagramme cliquable)

  • setResolution : la résolution par défaut est SVG : 960x540, de DEFAULT_540P à DEFAULT_4K

  • setXLabelDateFormat : voir Différents types d’étiquettes sur l’axe X (xLabels)

  • setMaxDataNumberToShowByDefault : limite le nombre de données affichées avant zoom

  • showTodayLine : chronologie uniquement, trace une ligne à la date du jour

Diagramme cliquable

Lorsqu’une action de clic est définie, cliquer sur une forme (barre, point, secteur, boîte, période…​) appelle l’action via Ajax. L’action peut retourner un bloc, typiquement une fenêtre modale, ou une page complète qui sera ouverte dans un nouvel onglet.

Ouverture d’une fenêtre modale lors du clic sur une barre
def salesPerMonth() {
    taackUiService.show(new UiBlockSpecifier().ui {
        diagram new UiDiagramSpecifier().ui {
            bar false, {
                labels 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'
                dataset 'Bikes', 12.0, 18.0, 9.0, 21.0, 25.0, 30.0
                dataset 'Scooters', 7.0, 5.0, 11.0, 8.0, 14.0, 12.0
                option DiagramOption.builder
                        .setTitle('Units sold per month')
                        .setClickAction(SalesController.&salesDetail as MC,  (1)
                                [year: 2026])
                        .build()
            }
        }
    }, buildMenu())
}

def salesDetail(String key, String x, String y, Integer year) {         (2)
    int units = new BigDecimal(y).intValue()
    Map<String, Integer> orders = [                                     (3)
            'Acme Corp': units.intdiv(2) as Integer,
            'Globex'   : units.intdiv(3) as Integer,
            'Initech'  : units - units.intdiv(2) - units.intdiv(3)
    ]
    taackUiService.show(new UiBlockSpecifier().ui {
        modal {                                                         (4)
            show new UiShowSpecifier().ui {
                field 'Product', key
                field 'Month', "$x $year".toString()
                field 'Units sold', y
            }
            table new UiTableSpecifier().ui {
                header {
                    label 'Order'
                    label 'Customer'
                    label 'Units'
                }
                orders.eachWithIndex { Map.Entry<String, Integer> o, int i ->
                    row {
                        rowField "SO-$year-$x-${i + 1}".toString()
                        rowField o.key
                        rowField o.value
                    }
                }
            }
        }
    })
}
1 Action appelée au clic, avec des paramètres optionnels (ou un identifiant)
2 key est le nom de la série (dataset), x l’étiquette sur l’axe X et y la valeur ; year provient des paramètres passés à setClickAction
3 Données fictives, habituellement une requête sur vos objets du domaine
4 L’action renvoie une fenêtre modale, affichée par-dessus le diagramme
diag dsl click modal
Figure 1. Clic sur la barre "Bikes" du mois de mai

Autres façons de coder

Différents types d’étiquettes sur l’axe X (xLabels)

Les étiquettes de l’axe X peuvent être de 3 types :

  • Chaîne de caractères (String, discret)

  • Nombre (Number, continu)

  • Date (Date, continu)

diagram new UiDiagramSpecifier().ui({
    line { // X axis: String
        labels "T1", "T2", "T3"
        dataset "test", 10.0, 20.1, 30.0
    }
    line { // X axis: Number
        labels 1.5, 1.7, 3.5
        dataset "test", 10.0, 20.1, 30.0
    }
    line { // X axis: Date
        Date date1 = new Date() // now (2025-02-28 10:55)
        Date date2 = new Date(date1.getTime() + 1000*60*60*2) // 2 hours later
        Date date3 = new Date(date1.getTime() + 1000*60*60*10) // 10 hours later
        labels date1, date2, date3
        dataset "test", 10.0, 20.1, 30.0
        option DiagramOption.builder
                .setXLabelDateFormat(DiagramXLabelDateFormat.HOUR) (1)
                .build()
    }
})
1 DiagramXLabelDateFormat : définit le format de date à afficher, ainsi que l’unité d’intervalle minimale (car l’axe X est continu)

screenshot dsl diagram xLabels type

Deuxième façon de fournir les coordonnées des données

Souvent utilisée pour un axe X continu sur lequel les différentes séries ont des coordonnées X différentes.

diagram new UiDiagramSpecifier().ui({
    // Normal way: different datasets have same X coordinates
    line {
        labels 1.5, 1.7, 3.5

        // 3 data: (1.5, 10.0), (1.7, 20.1), (3.5, 30.0)
        dataset "test1", 10.0, 20.1, 30.0

        // 3 data: (1.5, 1.0), (1.7, 2.0), (3.5, 3.0)
        dataset "test2", 1.0, 2.0, 3.0
    }

    // Second way: different datasets have different X coordinates
    line {
        // 3 data: (1.5, 10.0), (1.7, 20.1), (3.5, 30.0)
        dataset "test1", [1.5: 10.0, 1.7: 20.1, 3.5: 30.0]

        // 2 data: (1.5, 1.0), (6.1, 2.0)
        dataset "test2", [1.5: 1.0, 6.1: 2.0]
    }
})

screenshot dsl diagram coordinate

DSL pour afficher le nombre de données à intervalles réguliers

Nous avons un grand nombre d’objets et souhaitons obtenir un diagramme montrant le nombre d’objets année par année (ou mois par mois / jour par jour / heure par heure) selon la dateCreated de l’objet.

DSL à utiliser
    /**
     * Group the given dates according to DiagramXLabelDateFormat, then count every group and put the result as data to draw.
     *
     * For example:
     *      Knowing DiagramXLabelDateFormat.MONTH (Defined by {@link #labels(DiagramXLabelDateFormat dateFormat)}),
     *      and being given dates: 2025-01-01, 2025-01-10, 2025-01-20, 2025-02-01, 2025-02-10, 2025-03-01.
     *
     *      So they are divided to 3 groups with their own count: [2025-01: 3, 2025-02: 2, 2025-03: 1].
     *      The groups will be used as data to draw:
     *          - xLabels = ["2025-01", "2025-02", "2025-03"]
     *          - yDataList = [3.0, 2.0, 1.0]
     *
     * @param key
     * @param dates
     */
    void dataset(final String key, final Date... dates)
Code d’utilisation du DSL
diagram new UiDiagramSpecifier().ui({
    List<Claim> claims = Claim.findAll()
    bar {
        dataset "Claim", claims.collect { it.dateCreated } as Date[]
        option DiagramOption.builder
                .setXLabelDateFormat(DiagramXLabelDateFormat.MONTH) // show claim count month-by-month
                .build()
    }
})
Diagramme

screenshot dsl diagram count object

Parties dynamiques (uniquement en HTML)

Zoom (horizontal)

Placez la souris sur le diagramme, puis faites tourner la molette tout en maintenant la touche CTRL enfoncée.

  • CTRL + molette vers le haut pour zoomer.

  • CTRL + molette vers le bas pour dézoomer.

Défilement (horizontal)

Placez la souris sur le diagramme, maintenez le bouton gauche de la souris enfoncé, puis déplacez la souris horizontalement.

Les bornes minimale et maximale du défilement sont limitées

Infobulle (Tooltip)

La valeur d’un diagramme en barres/lignes/…​ n’est pas affichée de manière statique par défaut. En plaçant la souris sur n’importe quelle forme, une infobulle apparaît dynamiquement et affiche toutes les informations relatives à la forme ciblée.

screenshot dsl diagram tooltip

Légende cliquable

Cliquer sur la légende d’une série de données permet de masquer ou d’afficher la série correspondante.

Hiérarchie des symboles DSL

Diagram
Figure 2. Diagramme de hiérarchie des symboles pour Diagram DSL