Feuilles de style

Depuis Gaphor 2.0, il est possible d’obtenir une apparence différente des diagrammes grâce aux feuilles de style. Ces feuilles de style utilisent la syntaxe des feuilles de style en cascade (CSS). CSS est utilisé pour décrire la présentation d’un document écrit dans un langage de balisage, et est le plus souvent utilisé avec HTML pour les pages web.

Sur la page d’accueil CSS du W3C, CSS est décrit comme suit :

Les feuilles de style en cascade (CSS) sont un mécanisme simple permettant d’ajouter du style (par exemple, fonts, colors, spacing) aux documents Web.

Son application va cependant bien au-delà des documents web. Gaphor utilise en effet le CSS pour fournir des éléments de style aux éléments des diagrammes. Les CSS nous permettent de modifier l’aspect visuel de nos diagrammes. Il est par exemple possible de modifier les couleurs et les styles de ligne pour faciliter la lecture des diagrammes.

Comme il s’agit d’un diagramme et non d’un document HTML, certaines fonctions CSS ont été laissées de côté.

Le style fait partie du modèle, donc toutes les personnes travaillant sur un modèle auront le même style. Pour modifier le style, appuyez sur le bouton de la page d’outils dans le coin supérieur droit de gaphor :

Bouton pour accéder au code du style

Voici un exemple simple de modification de la couleur d’arrière-plan d’une classe :

class {
  background-color: beige;
}
fond beige

Ou changer la couleur d’un composant, uniquement lorsqu’il est imbriqué dans un nœud :

node component {
  background-color: skyblue;
}
composant imbriqué

Le diagramme lui-même est également exprimé sous la forme d’un nœud CSS. Il est assez facile de définir un style « sombre » :

diagram {
  background-color: #343131;
}

* {
  color: white;
  text-color: white;
}
style sombre

Ici, vous voyez déjà le premier attribut personnalisé : text-color. Cette propriété vous permet de contrôler la couleur du texte dessiné dans un élément. color est utilisé pour les lignes (strokes) qui constituent la mise en page d’un élément de diagramme.

Sélecteurs pris en charge

Étant donné qu’il s’agit de diagrammes et de modèles, nous n’avons pas besoin de toutes les fonctions CSS. Vous trouverez ci-dessous un résumé de toutes les fonctionnalités CSS prises en charge par Gaphor.

*

Tous les éléments du diagramme, y compris le diagramme lui-même.

node component

Tout élément de composant descendant d’un nœud.

node > component

Un élément de composant qui est un enfant d’un nœud.

.item

Chaque élément du diagramme se voit attribuer la classe « item ». Cela permet de les distinguer facilement, par exemple, des éléments de nom.

generalization[subject]

Un élément de généralisation avec un sujet présent.

class[name=Foo]

Une classe portant le nom « Foo ».

diagram[name^=draft]

Un diagramme dont le nom commence par « draft ».

diagram[name$=draft]

Un diagramme avec un nom se termine par « draft ».

diagram[name*=draft]

Un diagramme dont le nom contient le texte « draft ».

diagram[name~=draft item]

Un diagramme dont le nom est « draft » (brouillon) ou « item » (élément).

diagram[name|=draft]

Un diagramme dont le nom est « draft » (brouillon) ou commence par « draft-« .

:focus

L’élément focalisé. D’autres pseudo classes sont :

  • :active éléments sélectionnés

  • :hover (survol) pour l’élément sous la souris

  • :drop (déposé) si un élément est déplacé et peut être déposé sur cet élément

  • :disabled (désactivé) si un élément est grisé lors du déplacement de la poignée

:empty (vide)

Un nœud ne contenant aucun nœud enfant dans le diagramme.

:root (racine)

Se réfère au diagramme lui-même.

Ceci ne s’applique qu’au diagramme

:first-child (premier enfant)

Un nœud est le premier élément d’un groupe de frères et sœurs.

:has()

L’élément contient l’un des sélecteurs fournis.

Par exemple, node:has(component) : un noeud contenant un élément de composant.

:is()

Correspond à l’un des sélecteurs fournis.

Par exemple, :is(node, subsystem) > component : un nœud ou un sous-système.

:not()

Négation du sélecteur.

Par exemple, :not([subject]) : Tout élément qui n’a pas de « sujet « .

::after

Fournit un contenu supplémentaire après un texte. Seule la propriété content est supportée.

  • La spécification officielle des sélecteurs d’attributs CSS3.

  • Gaphor fournit le sélecteur d’attribut |= par souci d’exhaustivité. Il n’est probablement pas très utile dans ce contexte.

  • Veuillez noter que Gaphor CSS ne prend pas en charge les identifiants pour les éléments de diagramme, de sorte que la syntaxe CSS pour les identifiants (#some-id) n’est pas utilisée. De même, la syntaxe de classe (.some-class) n’est actuellement pas prise en charge.

Propriétés de style

Gaphor prend en charge un sous-ensemble de propriétés CSS ainsi que quelques propriétés spécifiques à l’outil. L’interpréteur de feuilles de style est relativement simple. Toutes les largeurs, hauteurs et tailles sont exprimées en pixels. Il n’est pas possible d’utiliser des déclarations de style complexes, comme la propriété font en HTML/CSS qui peut contenir la famille, la taille et le poids de la police.

Certaines propriétés sont héritées du style parent. Le parent est souvent un diagramme. Lorsque vous définissez une color`` ou une ``font-family sur diagram, cela se propagera aux éléments contenus dans le diagramme.

Couleurs

background-color

Exemples :

background-color: azure;

background-color: rgb(255, 255, 255) ;

background-color: hsl(130, 95%, 10%) ;

color

Couleur utilisée pour les lignes. (hérité)

text-color

Couleur du texte. (hérité)

Obsolète depuis la version 2.23.0: Utilisez la couleur si possible.

opacity

Facteur d’opacité de la couleur (0.0 - 1.0), appliqué à toutes les couleurs.

  • Une couleur peut être n’importe quel code couleur CSS3, comme décrit dans la documentation CSS. Gaphor supporte toutes les notations de couleur : rgb(), rgba(), hsl(), hsla(), le code hexagonal (#ffffff) et les noms de couleurs.

Texte et polices

font-family

Un nom de police unique (par exemple sans, serif, courier). (hérité)

font-size

Une taille absolue (par exemple 14) ou une valeur de taille (par exemple small). (inherited)

font-style

Soit normal ou italic. (inherited)

font-weight

Soit normal ou bold. (inherited)

text-align

Soit left, center, right. (inherited)

text-decoration

Soit non ou souligné.

vertical-align

Alignement vertical du texte.

Soit top, middle ou bottom.

vertical-spacing

Définir l’espacement vertical pour les éléments de type icône (acteurs, état de départ).

Exemple : vertical-spacing : 4.

white-space

Modifie le comportement de retour à la ligne du texte. (hérité)

  • font-family ne peut être qu’un seul nom de police, et non une liste de noms (de repli), comme c’est le cas pour HTML.

  • font-size peut être un nombre ou CSS absolute-size values. Seules les valeurs x-small, small, medium, large et x-large sont supportées.

Dessin et espacement

border-radius

Rayon pour les rectangles : border-radius : 4.

dash-style

Style pour les lignes en pointillés : dash-style : 7 5.

justify-content

Alignement du contenu des boîtes.

Soit début, fin, centre ou étiré.

line-style

Soit normal, soit sloppy [factor].

line-width

Définir la largeur des lignes : largeur ligne : 2. (hérité)

min-height

Fixe la hauteur minimale d’un élément : min-height : 50.

min-width

Fixe la largeur minimale d’un élément : min-width : 100.

max-width

Définir la largeur maximale (champs de texte uniquement) : max-width : 100.

padding

Style CSS d’espacement de chaque coté (top, right, bottom, left).

Exemple: padding: 3 4.

  • La propriété padding est définie par des nombres entiers compris entre 1 et 4. Il n’est pas nécessaire d’utiliser d’unité (px, pt, em). Toutes les valeurs sont exprimées en pixels.

  • dash-style est une liste de nombres (ligne, espace, ligne, espace, …)

  • line-style n’a d’effet que lorsqu’il est défini sur un diagramme. Un facteur de négligence peut être fourni entre -2 et 2.

Pseudo-éléments

Actuellement, seul le pseudo-élément ::after est pris en charge.

content

Contenu supplémentaire à afficher après un texte.

Variables

Depuis Gaphor 2.16.0, vous pouvez utiliser des variables CSS dans vos feuilles de style.

Cela vous permet de définir des valeurs souvent utilisées de manière plus générique. Pensez à des choses comme le style des tirets et les couleurs.

La fonction var() a quelques limitations :

  • Les valeurs ne peuvent pas avoir de valeur par défaut.

  • Les variables ne peuvent pas avoir une variable comme valeur.

Exemples :

diagram {
  --bg-color: whitesmoke;
  background-color: var(--bg-color);
}

diagram[diagramType=sd] {
  --bg-color: rgb(200, 200, 255);
}

Tous les diagrammes ont un fond blanc. Les diagrammes de séquence ont un fond bleu.

Questions sur les médias

Depuis la version 2.16.0, Gaphor prend en charge les modes sombre et clair. Les couleurs foncées et claires sont exclusivement utilisées pour l’édition à l’écran. Lors de l’exportation d’images, la palette de couleurs par défaut est appliquée. Les jeux de couleurs peuvent être définis à l’aide des requêtes @media. La requête officielle prefers-color-scheme = dark est prise en charge, ainsi qu’un mode sombre plus pratique.

/* The background you see in exported diagrams: */
diagram {
  background-color: transparent;
}

/* Use a slightly grey background in the editor: */
@media light-mode {
  diagram {
    background-color: #e1e1e1;
  }
}

/* And anthracite a slightly grey background in the editor: */
@media dark-mode {
  diagram {
    background-color: #393D47;
  }
}

Styles de diagramme

Seules quelques propriétés peuvent être définies pour un diagramme, à savoir background-color et line-style. Le style du diagramme est défini séparément de celui des éléments du diagramme. Il est ainsi possible de définir la couleur d’arrière-plan pour les diagrammes de manière spécifique. Le style de ligne peut être la ligne droite normale, ou un style plus ludique « sloppy ». Pour le style négligé, il est possible de fournir un facteur optionnel d’ondulation permettant de définir le niveau d’ondulation de la ligne. La valeur par défaut est 0,5, correspondant à une ligne droite. La valeur doit être comprise entre -2,0 et 2,0. Les valeurs comprises entre 0,0 et 0,5 produisent un effet subtil.

Éléments du modèle CSS

Gaphor possède de nombreux éléments de modèle. Comment savoir quel élément doit être stylisé ?

Gaphor ne stylise que les éléments présents dans le modèle, vous devez donc être explicite sur leurs noms. Par exemple, Componenthérite de la Class dans le modèle UML, mais changer la couleur d’une classe ne la change pas pour un Component.

Si vous survolez un bouton de la boîte à outils (dans la section inférieure gauche), une fenêtre contextuelle apparaîtra avec le nom de l’élément et un raccourci. En règle générale, vous pouvez utiliser le nom du composant, qui doit être collé ensemble, comme le nom dans la feuille de style. Vous pouvez adresser un Composant comme componentou unCas d’utilisation comme usecase. La correspondance des noms est insensible à la casse. Les noms CSS sont écrits en minuscules par défaut.

Cependant, comme les noms des éléments CSS sont dérivés des noms utilisés dans Gaphor, il y a quelques exceptions.

Profile

Groupe

Élément

Élément CSS

*

*

nom de l’élément

nom de l’élément sans espace

Par exemple, class, usecase.

UML

Classes

toutes les associations

association

UML

Composants

Dispositif/Nœud

node

UML

Actions

Décision/Fusion de Nœud

decisionnode

UML

Actions

Fork/Joindre Nœud

forknode

UML

Actions

Couloir d’activité (Swimlane)

partition

UML

Interactions

Message réflexif

message

UML

États

Pseudo-état initial

pseudostate

UML

États

Histoique Pseudo-État

pseudostate

UML

Profiles

Métaclasse

class

Modèle C4

Modèle C4

Personne

c4person

Modèle C4

Modèle C4

Système logiciel

c4container[type="Software System"]

Modèle C4

Modèle C4

Composant

c4container[type="Component"]

Modèle C4

Modèle C4

Conteneur

c4container[type="Container"]

Modèle C4

Modèle C4

Conteneur : Base de données

c4database

SysML

Blocs

TypeValeur

datatype

SysML

Blocs

Primitive

datatype

SysML

Exigences

Exigence dérivée

derivedreq

RAAML

FTA

Porte…toute/ET/OU

and, or, etc.

Idées

Voici quelques idées qui vont au-delà du changement de couleur ou de police. Les exemples suivants nous permettent d’approfondir la structure du modèle de Gaphor afin de révéler davantage d’informations aux utilisateurs.

Pour créer votre propre expression, vous pouvez utiliser la console ( Icône de menu → Tools → Console). Envoyez-nous un message sur Gitter et nous serons heureux de vous aider.

Le paquet de projets

Tous les diagrammes du paquet « Drafts » doivent être dessinés en utilisant des lignes négligées :

diagram[owner.name=drafts] {
  line-style: sloppy 0.3;
}

diagram[owner.name=drafts] * {
  font-family: Purisa; /* Or use some other font that's installed on your system */
}
style brouillon

Envelopper les attributs longs, les opérations et les valeurs des stéréotypes

Les valeurs des attributs sont parfois un peu longues. Par défaut, Gaphor n’enveloppe pas le texte. Si vous le souhaitez, vous pouvez ajouter ce petit extrait pour envelopper le texte des attributs longs des classes. Vous pouvez bien sûr également l’appliquer à d’autres types.

class * {
 white-space: normal;
}
attribut long enveloppant

Relations non connectées

Tous les éléments d’un diagramme qui ne sont pas soutenus par un élément du modèle doivent être dessinés en rouge foncé. Cela permet de repérer les relations mal connectées, telles que la généralisation, l’implémentation et la dépendance. Ces éléments ne seront soutenus par un élément de modèle que lorsque les deux extrémités de la ligne seront connectées. Cette règle exclut les éléments simples, tels que les lignes et les boîtes, qui ne sont jamais soutenus par un élément de modèle.

:not(:is(:root, line, box, ellipse, commentline))[subject=""] {
  color: firebrick;
}
relation sans lien

lignes Flux de Contrôle Solide

Dans Gaphor, les lignes de Flux de Contrôle suivent le style SysML : en pointillés. Si vous voulez ou devez suivre strictement les spécifications officielles d’UML, vous pouvez simplement créer des lignes pleines.

controlflow {
  dash-style: 0;
}
flux de contrôle

Mise en évidence de la note de service

Tous les commentaires commençant par la phrase « À faire » (« todo ») peuvent être mis en évidence dans une couleur différente pour chaque utilisateur. Cela peut vous permettre de prendre conscience qu’il vous reste du travail à effectuer pour finaliser le diagramme.

comment[body^="TODO"] {
  background-color: skyblue;
}
note de tâche surlignée

Mettre l’accent sur les classes et les opérations abstraites

Il se peut que la police italique utilisée ne permette pas de distinguer les classes ou les opérations concrètes des opérations abstraites. Pour ce faire, nous vérifions si l’attribut isAbstract est défini sur l’élément en question :

:is(name, operation)[isabstract]::after {
  content: " {abstract}"
}
Mettre l'accent sur les éléments abstraits

Feuille de Style du Système

/* Gaphor diagram style sheet */

* {
  --opaque-background-color: white;
  background-color: transparent;
}

:not(diagramframe):drop {
  color: #1a5fb4;
  line-width: 3;
}

:disabled {
  opacity: 0.5;
}

@media light-mode {
  * {
    --opaque-background-color: #fafafa;
  }
}

@media dark-mode {
  * {
    --opaque-background-color: #242424;
    color: white;
  }

  :drop {
    color: #62a0ea;
  }
}

:root {
  color: black;
  font-family: sans;
  font-size: 14 ;
  line-width: 2;
  padding: 0;
}

diagramframe {
  justify-content: start;
}

:is(:root, diagramframe) > pentagon {
  line-width: 1;
  background-color: var(--opaque-background-color);
}

:is(:root, diagramframe) > pentagon > diagramtype {
  font-weight: bold;
  padding: 4 0 4 4;
}

:is(:root, diagramframe) > pentagon > stereotypes {
  padding: 4 0 4 4;
}

:is(:root, diagramframe) > pentagon > name {
  padding: 4;
}

:has(.item) compartment:first-child {
  justify-content: start;
}

/* Relationships */

commentline,
c4dependency,
dependency,
interfacerealization,
include,
extend,
packageimport,
lifetime,
satisfy,
derivereqt,
trace,
verify,
refine {
 dash-style: 7 5;
}

dependency[on_folded_interface = true],
interfacerealization[on_folded_interface = true] {
  dash-style: 0;
}

/* General */

comment {
  text-align: left;
  vertical-align: top;
  padding: 4 16 4 4;
}

comment stereotypes {
  text-align: center;
}

comment body {
  padding: 0;
}

diagram > icon {
  padding: 4;
  border-radius: 4;
}

diagram > type {
  font-weight: bold;
}

metadata {
  justify-content: stretch;
  text-align: left;
}

metadata cell {
  padding: 4;
}

metadata heading {
  font-weight: bold;
  font-style: normal;
  font-size: small;
}

pentagon {
  padding: 4;
  justify-content: start;
  text-align: left;
}

/* UML */

controlflow {
  dash-style: 9 3;
}

objectnode > icon {
  padding: 4 12;
}

decisionnode > type {
  font-size: small;
}

proxyport > icon,
activityparameternode,
executionspecification {
  background-color: var(--opaque-background-color);
}

partition {
  padding: 4 12 4 12;
  justify-content: stretch;
}

package {
  padding: 24 12 4 12;
}

interaction {
  justify-content: start;
}

activity {
  padding: 4 12;
  border-radius: 20;
  justify-content: start;
}

activityparameternode {
  padding: 4 12;
  min-width: 120;
  text-align: center;
}

action,
valuespecificationaction {
  padding: 4 12;
  border-radius: 15;
}

callbehavioraction {
  padding: 4 24 4 12;
  border-radius: 15;
}

sendsignalaction {
  padding: 4 24 4 12;
}

accepteventaction {
  padding: 4 12 4 24;
}

usecase {
  padding: 4;
}

swimlane {
  min-width: 150;
  padding: 4 12 4 12;
  justify-content: start;
  white-space: normal;
}

association > end {
  font-size: x-small;
  padding: 4;
}

/* SysML */

requirement {
  justify-content: start;
}

requirement text {
  white-space: normal;
}

directedrelationshippropertypath {
  dash-style: 7 5;
}

/* Classifiers */

compartment:first-child {
  padding: 12 4;
}

compartment + compartment {
  padding: 4;
  min-height: 8;
  text-align: left;
  justify-content: start;
  white-space: nowrap;
}

artifact compartment:first-child,
component compartment:first-child {
  padding: 12 24 12 4;
}

state compartment:first-child {
  padding: 4;
}

:has(.item),
:has(compartment + compartment),
:has(regions) {
  justify-content: start;
}

regions {
  justify-content: stretch;
}

region {
  padding: 4;
  min-height: 100;
  justify-content: start;
  text-align: left;
}

region + region {
  dash-style: 7 3;
}

and name,
xor name,
intermediateevent name,
dormantevent name,
basicevent name,
houseevent name,
topevent name,
inhibit name,
conditionalevent name,
zeroevent name,
or name,
not name,
transferin name,
transferout name,
undevelopedevent name,
seq name,
majorityvote name,
unsafecontrolaction name,
operationalsituation name,
controlaction name,
interfaceblock name,
block name,
property name,
requirement name,
c4person name,
c4database name,
c4container name,
package name,
enumeration name,
interface name,
class name,
datatype name,
component name,
statemachine name,
usecase name,
actor name,
artifact name,
node name {
  font-weight: bold;
}

name[isabstract] {
  font-style: italic;
}

from {
  font-size: x-small;
}

activity > :is(name, stereotypes) {
  text-align: left;
}

compartment heading {
  padding: 0 0 4 0;
  font-size: x-small;
  font-style: italic;
  text-align: center;
}

operation[isabstract] {
  font-style: italic;
}

attribute[isstatic],
operation[isstatic] {
  text-decoration: underline;
}

property:not([aggregation="composite"]) {
  dash-style: 7 5;
}

/* Attached */

:has(icon)[connected_side] {
  text-align: right;
  vertical-align: top;
}

:has(icon)[connected_side="left"] {
  text-align: left;
}

:has(icon)[connected_side="bottom"] {
  vertical-align: bottom;
}

/* C4 model */

c4container, c4person {
  padding: 4 4 4 4;
}

c4database {
  padding: 20 4 4 4;
}

:is(c4container, c4database, c4person):has(.item) {
  justify-content: end;
}

:is(c4container, c4database, c4person):has(.item) > :is(name, technology) {
  text-align: left;
}

c4dependency name {
  max-width: 150;
}

:is(c4container, c4database, c4dependency, c4person) technology {
  font-size: x-small;
}

:is(c4container, c4database, c4person) description {
  padding: 4 4 0 4;
}