Comment créer une forme personnalisée dans le code source d'un fichier ?

    From The Document Foundation Wiki

    Introduction

    Ce tutoriel s'adresse aux utilisateurs avancés qui sont prêts à entrer dans le code XML d'un fichier au format OpenDocument (ODT pour le texte, ODS pour les classeurs, ODP pour les présentations, ODG pour les dessins). Il expose comment créer une nouvelle forme personnalisée, en particulier dans un dessin. Ceci nécessite d'éditer le code source XML du fichier. Cependant, aucune connaissance du langage XML, ou de tout autre langage de programmation, n'est nécessaire. Aucune macro n'est utilisée. Ce tutoriel est en même temps une introduction aux spécifications ODF des formes personnalisées (custom shapes).

    Nouveau document

    Format du fichier

    LibreOffice utilise pour enregistrer les documents le format OpenDocument (ODF). Il s'agit en fait d'un fichier compressé au format ZIP contenant des fichiers répartis dans une arborescence. Pour plus d'informations sur le format ODF, référez-vous à l'entrée de la FAQ : LibreOffice et le XML. La modification du code XML d'un fichier demande alors de décompresser l'arborescence du ZIP, d'éditer le code XML, d'enregistrer et de recompresser l'ensemble (dans le bon ordre pour faire un fichier conforme). Cela devient vite fastidieux si de nombreux essais-erreurs doivent être réalisés.

    En plus du format OpenDocument, LibreOffice permet d'enregistrer au format Flat OpenDocument (FODF). Dans ce cas, le fichier généré dispose d'une extension avec un 'F' en plus (FODT, FODS, FODP, FODG) et est un simple fichier texte contenant tout le code XML ainsi que l'ensemble des autres fichiers. Pour éditer le code XML, plus besoin de passer par les étapes de compression/décompression. C'est bien sûr ce format que nous vous encourageons à utiliser dans le cadre de ce tutoriel. Une fois la forme obtenue, vous pourrez enregistrer votre fichier au format OpenDocument classique.

    Si vous devez utiliser le format OpenDocument, n'oubliez cependant pas de désactiver l'option Optimisation de la taille pour le format OpenDocument dans le menu Outils ▸ Options ▸ LibreOffice ▸ Chargement/Enregistrement ▸ Général : cela permettra d'obtenir un code XML lisible par un être humain.

    Nouveau dessin

    • Créez un nouveau dessin.
    • Dessinez un rectangle. Utilisez l'outil Rectangle de la barre d'outils Formes de base.
    • Renommez la forme rectangle MaForme ou tout autre nom qui vous paraitrait plus approprié :
      • cliquez droit sur la forme et sélectionnez  ▸ Nom 
      • renseignez le nom choisi.
    Note : il n'est pas indispensable de renommer la forme, mais cela permettra de la retrouver plus facilement.
    • Enregistrez le fichier, de préférence au format Flat OpenDocument : modifiez le type en OpenDocument Drawing (Flat XML) (.fodg), par exemple Début.fodg.
    Note : prendre comme point de départ non pas un fichier vide, mais un fichier contenant une forme personnalisée présente certains avantages : vous n'avez pas à vous préoccuper du document lui-même, comment insérer la forme dans une page et une couche, ou comment appliquer certains styles.
    • Si vous souhaitez modifier la forme personnalisée au travers de son code XML, vous devez fermer le fichier. Si vous ne souhaitez que regarder le code, il n'est même pas nécessaire de le faire.

    Examiner le code

    Éditeur de texte

    Pour examiner le code, vous pouvez utiliser n'importe quel éditeur de texte capable d'écrire le codage UTF-8. Il est cependant recommandé d'utiliser un éditeur de texte reconnaissant la syntaxe XML, en la coloriant et en gérant les nœuds. Par exemple sous Windows, le logiciel libre Notepad++ fait très bien ce travail. On peut également citer XML Notepad 2007 de Microsoft.

    Avec Notepad++ :

    • dans l'explorateur de fichiers, retrouvez votre fichier ;
    • cliquez droit sur le fichier FODG et sélectionnez  ▸ Edit with Notepad++ ;
    • de nombreux langages sont reconnus par Notepad++ ; comme l'extension FDOG n'est pas connue de Notepad++, il faut lui préciser que le fichier est en langage XML,  :
      • soit en sélectionnant le menu Langage ▸ XML (vous devrez le refaire à chaque ouverture du fichier),
      • soit en modifiant les paramètres de Notepad++ :
        • sélectionnez le menu Paramètres ▸ Configurateur de coloration syntaxique,
        • sélectionnez le langage XML,
        • ajoutez dans le champ Ext. utilisateur : les extensions fodg, fodt, fods et fodp (Notepad++ reconnaitra désormais automatiquement le format de ces fichiers).

    Le code XML

    Une petite partie du fichier nous intéresse : celle concernant la forme personnalisée. Voici cependant une rapide description des autres parties, dont la connaissance n'est malgré tout pas indispensable.

    La première ligne contient le prologue qui indique qu'il s'agit d'un fichier XML classique :

    <?xml version="1.0" encoding="utf-8"?>
    

    Le reste du code est, comme pour tout langage à balises, de la forme

    <balise>information</balise>
    

    balise est le nom d'une balise et information l'information pour cette balise. Les balises peuvent être imbriquées les unes dans les autres, ce qui rend le document difficile à lire pour un être humain. Pour faciliter la lecture, l'éditeur de texte doit avoir créé des nœuds à chaque ouverture de balise. Un symbole - indique un nœud ouvert et un symbole + indique un nœud fermé. Dans ce dernier cas, tout le texte compris entre la balise ouvrante et la balise fermante est masqué.

    Après une ligne vide, la première balise <office:document...> contient l'ensemble du document. Si vous fermez le nœud associé à cette balise tout l'affichage se résume à la première ligne.

    La balise <office:meta> contient les informations sur le document, puis <office:settings> contient les options du document. En fermant ce nœud, près d'une centaine de lignes sans intérêt pour ce que nous voulons faire sont masquées.

    La balise <office:script> va stocker les macros enregistrées avec le document.

    Les balises <office:styles> et <office:automatic-styles> vont contenir tous les styles automatiques et personnalisés disponibles pour ce document. Nous n'utiliserons pas ces parties du code, car il sera beaucoup plus facile d'utiliser LibreOffice lui-même pour mettre en forme les formes personnalisées.

    La balise <office:master-styles> contient les couches et les pages maitresses du document.

    Enfin la balise <office:body> annonce le contenu du document. Si vous avez fermé les balises précédentes, et sans retour à la ligne automatique, votre affichage doit ressembler à cette figure :

    Code XML d'une custom shape

    En entrant dans la balise <office:body>, on trouve <office:drawing> puis <draw:page...>, puis enfin <draw:custom-shape...>. On y est ! Sur la figure précédente, ce sont donc uniquement les lignes 346, 347 et 348 qui vont dessiner le rectangle et qui nous intéressent.

    L'élément custom-shape

    À l'opposé du langage OOXML avec ses abréviations, ODF est très bavard. Cela vous permettra de comprendre instinctivement beaucoup de choses. L'élément custom-shape a des attributs et quelques sous-éléments.

    Les attributs décrivent la relation avec la page de dessin. Il n'y a rien de spécifique aux custom-shapes, vous les trouverez pour tous les dessins.

    draw:style-name="gr1"
    La référence au style de graphique employé pour cette forme. Dans le style vous trouverez des informations telles que l'épaisseur du trait ou la couleur de remplissage.
    draw:text-style-name="P1"
    La référence au style de texte employé pour le texte dans la forme. Dans ce style vous trouverez la police employée par exemple.
    draw:layer="layout"
    Une page de Draw est constituée de plusieurs couches. La couche par défaut pour les formes est celle appelée “layout”. Les autres couches par défaut sont “background” et “controls”, mais vous pouvez également définir vos propres couches dans Draw.
    draw:name="MaForme"
    Vous le reconnaissez ? C'est le nom donné au rectangle.
    svg:width="9.5cm" svg:height="4cm"
    La taille de la forme.
    svg:x="1.5cm" svg:y="3cm"
    La position du coin haut gauche de la forme.
    Les quatre derniers attributs correspondent aux paramètres à régler dans la boite de dialogue Position et taille de la forme. Ils définissent le rectangle avec les poignées vertes entourant la forme lorsqu'elle est sélectionnée. Ces poignées sont bleues s'il s'agit d'une forme personnalisée. Cette information peut être étendue à l'aide d'un attribut svg:transform pour réaliser une rotation, un cisaillement ou tout autre matrice de transformation linéaire. La spécification ODF n'a pas créé sa propre définition pour ces attributs, mais utilise les attributs bien définis par les spécification SVG du consortium W3. À chaque fois que c'est possible, la spécification ODF utilise les spécifications SVG, ou au moins les suit d'aussi près que possible.
    <text:p />
    Dans cette balise, apparait le texte qui a été entré dans la forme. Comme le rectangle ne contient pas de texte, l'élément est vide.
    <draw:enhanced-geometry ... />
    C'est cette partie qui distingue la forme personnalisée des autres objets et qui est spécifique aux custom-shapes. Nous allons opérer nos modifications à cet endroit. Le rectangle étant une forme très simple, l'élément n'a que quelques attributs mais pas de sous-éléments.
    svg:viewBox
    Cet élément définit le système de coordonnées local. Il ne définit pas la taille de la forme, qui a été défini précédemment. Les deux premiers nombres sont les valeurs minimales en abscisse (x) et ordonnée (y) ; ils correspondent au coin haut gauche. Les troisième et quatrième nombres correspondent à la largeur et la hauteur dans les coordonnées locales. Si vous omettez ce paramètre, LibreOffice utilise des valeurs minimales en x et y de 0 et des valeurs de hauteur/largeur de 21600. Vous pouvez utiliser des valeurs plus petites si vous préférez, car les coordonnées peuvent être des réels. Faites cependant attention si vous devez partager vos fichiers avec des utilisateurs de PowerPoint, vous devriez conserver ces valeurs de 21600, car PowerPoint ne peut utiliser que des valeurs entières dans ses versions actuelles. De même, des valeurs négatives pour les minima en x et y ne sont pas recommandées (voir le bogue i#121453).
    draw:type
    Cet élément définit le type de forme. LibreOffice l'utilise pour faire le lien avec les formes qui ont une correspondance avec les formes personnalisées de Microsoft et les formes prédéfinies en OOXML. Ainsi lors de l'export d'un document dans un format de MS-Office, la forme est correctement exportée. Les formes sans ces traitements spéciaux devraient avoir le type par défaut non-primitive.
    draw:enhanced-path
    Cet élément décrit la ligne qui dessine la forme. Vous pouvez imaginer votre forme personnalisée comme un canevas rectangulaire, sur lequel des lignes sont dessinées. Ces lignes constituent le path (chemin en français). Les commandes pour construire un chemin sont basées sur les définitions de chemin SVG, mais ne sont pas identiques à elles. C'est pourquoi le mot clé draw est utilisé à la place de svg. Une restriction concerne les coordonnées : les coordonnées employées pour les points sont toujours absolues. Par conséquent, les commandes sont toutes en majuscules.
    La plupart des commandes commence à dessiner à partir de la dernière position résultant des commandes précédentes. C'est pourquoi le chemin commence la plupart du temps par la commande move M. Une ligne droite est dessinée par la commande line to L. Et la commande Z ferme le chemin : le dernier point rejoint le premier. Pour une liste complète des commandes disponibles, référez-vous à la section 19.145 de la spécification ODF ou à la liste ci-dessous.

    Utilisation de l'élément custom-shape

    Nous allons maintenant réaliser un exemple d'application en créant une parabole simple d'équation y=x2 dans la plage [-3;3]. La valeur en y sera donc sur la plage [0;9].

    1. Modifiez la valeur de l'attribut draw:name à Parabole.
    2. L'amplitude en abscisse est de 6 et en ordonnée de 9 : modifiez la taille de la boite de visualisation svg:viewBox="0 0 6 9".
    3. Le type doit être modifié, car sinon il y aura toujours un rectangle de tracé : draw:type="non-primitive" ou toute autre valeur non utilisée.
      Il faut maintenant translater les coordonnées mathématiques (dont l'origine est au centre en bas) dans le système de coordonnée local (dont l'origine est dans le coin haut gauche).
      Une parabole se trace avec une courbe de Bézier quadratique, dont la commande est Q x1 y1 x y : le point de départ est le point courant, le point (x1;y1) est le point de construction, à placer en (0;-9) dans notre cas, soit (3;18) pour les coordonnées locales, et le point (x;y) le point terminal, (3;9) dans notre cas, soit (6;0) pour les coordonnées locales.
      Figure 1 : Passage des coordonnées mathématiques aux coordonnées de l'écran
    4. L'attribut draw:enhanced-path="..." doit donc commencer la commande M x y pour placer le point de départ (-3;9), qui correspond aux coordonnées locales (0;0) :
      draw:enhanced-path="M 0 0"
    5. La suite de l'attribut correspond à la courbe de Bézier :
      draw:enhanced-path="M 0 0 Q 3 18 6 0"
      Notez que le point de contrôle sort de la fenêtre définie par l'attribut svg:viewBox. Les points de la courbe peuvent également sortir de cette fenêtre. Cela ne sera cependant pas forcément logique pour l'utilisateur.
    6. Il faut enfin terminer la courbe. Si on souhaite que la courbe soit fermée, il faut ajouter la commande Z, sinon on n'ajoute rien :
      draw:enhanced-path="M 0 0 Q 3 18 6 0 Z"

    Le code complet est donc :

    <draw:enhanced-geometry 
       svg:viewBox="0 0 6 9" 
       draw:type="non-primitive" 
       draw:enhanced-path="M 0 0 Q 3 18 6 0 Z" 
     />


    Note : certaines versions anciennes de LibO peuvent ne pas savoir interpréter la courbe de Bézier quadratique (commande Q). Il faut alors utiliser une courbe de Bézier cubique, commande C x1 y1 x2 y2 x y. Le point de départ est le point courant, les points (x1;y1) et (x2;y2) sont les points de construction, à placer en (-1;-3) et (1;-3) dans notre cas, soit (2;12) et (4;12) pour les coordonnées locales, et le point (x;y) le point terminal, (3;9) dans notre cas, soit (6;0) pour les coordonnées locales. Ce qui donne le code équivalent au code précédent :

    draw:enhanced-path="M 0 0 C 2 12 4 12 6 0 Z"
    

    La version 4.2 de LibreOffice permettra d'utiliser des virgules comme séparateur, ce qui rendra les longues chaînes de coordonnées beaucoup plus lisibles. Attention cependant à la compatibilité descendante pour les versions de LibO antérieures à la 4.2 et les versions d'AOO antérieures à la 4.0.

    Retour dans LibreOffice

    Enregistrer le fichier

    Si vous utilisez le format Flat OpenDocument (FODG), il vous suffit d'enregistrer votre fichier. Si votre éditeur de texte ne bloque pas le fichier, vous pouvez directement l'ouvrir dans LibreOffice. Si vous utilisez le format OpenDocument (ODG), vous devrez rezipper le fichier. Le tutoriel est ici.

    Utiliser la forme créée

    Dans LibreOffice, vous obtenez donc votre superbe parabole. Vous pouvez maintenant appliquer tous les styles de ligne (épaisseur, couleur,...) ou de remplissage qui vous conviennent, comme avec n'importe quelle forme prédéfinie. Vous pouvez élargir, rétrécir ou faire tourner la forme : ce sera toujours une parabole parfaite.

    Réutiliser et distribuer la forme

    Si vous êtes insatisfait de votre forme, il vous suffit de rééditer le fichier .FODG pour modifier les coordonnées des points.

    Si la forme vous convient, le moyen le plus simple pour l'avoir à disposition dans n'importe quel module est d'utiliser la Gallery. Voir Comment réutiliser un dessin à l'aide de la Gallery ?

    Si vous voulez diffuser votre dessin, il peut être suffisant d'envoyer un fichier ODG contenant votre forme. Mais si vous avez plusieurs formes, il peut être intéressant de diffuser votre collection sous forme d'extension de Gallery. Voir le tutoriel Comment créer une extension - Application à la création d'un thème pour la Gallery.

    Pour aller plus loin

    Liste des commandes pour draw:enhanced-path

    Selon la norme OpenDocument Format, à la section 19.145, les commandes disponibles sont :

    Commande Nom Paramètres Description
    A arcto (x1 y1 x2 y2 x3 y3 x4 y4) + Les points (x1;y1) et (x2;y2) définissent les coins de la boite délimitant une ellipse. Une ligne est tracée à partir du point courant jusqu'à l'angle de départ de l'arc. Cet angle est spécifié par le vecteur radial du point (x3;y3). L'arc est tracé dans le sens trigonométrique jusqu'à l'angle de fin spécifié par le point (x4;y4).
    B arc (x1 y1 x2 y2 x3 y3 x4 y4) + Identique à la commande A, sauf qu'il n'y a pas de ligne de tracée du point courant jusqu'à (x1;y1).
    C curveto (x1 y1 x2 y2 x y) + Dessine une courbe de Bézier cubique à partir du point courant jusqu'au point (x;y) en utilisant le point (x1;y1) comme point de contrôle pour le début de la courbe et le point (x2;y2) comme point de contrôle de la fin de la courbe.
    F nofill aucun Spécifie que l'ensemble des sous-chemins courant n'aura pas de remplissage.
    L lineto (x y) + Dessine un trait du point courant au point (x;y).
    M moveto (x y) + Démarre un nouveau sous-chemin à partir du point (x;y). Si d'autres coordonnées suivent, elles seront traitées comme une commande lineto.
    N endpath aucun Termine l'ensemble courant de sous-chemins. Les sous-chemins seront remplis en utilisant la règle de remplissage "paire/impaire". Les sous-chemins suivants seront remplis indépendamment.
    Q quadratic­curveto (x1 y1 x y)+ Dessine une courbe de Bézier quadratique à partir du point courant jusqu'au point (x;y) en utilisant le point (x1;y1) comme point de contrôle.
    S nostroke aucun Spécifie que l'ensemble de sous-chemins courant n'aura pas de hachure.
    T angle­ellipseto (x y w h t0 t1) + Dessine le segment d'une ellipse. L'ellipse est définie par son centre (x;y), sa taille (w=largeur, h=hauteur) et l'angle de départ t0 en degrés et l'angle de fin t1 en degrés. L'ellipse est dessinée dans le sens trigonométrique. Une ligne est tracée du point courant au point de départ.
    U angle­ellipse (x y w h t0 t1) + Identique à la commande T, sauf qu'il n'y a pas de ligne de tracée du point courant jusqu'au point de départ.
    V clockwise­arc (x1 y1 x2 y2 x3 y3 x y)+ Identique à la commande A, sauf que l'arc est tracé dans le sens des aiguilles d'une montre et qu'il n'y a pas de ligne de tracée du point courant au point (x1;y1).
    W clockwise­arcto (x1 y1 x2 y2 x3 y3 x y)+ Identique à la commande A, sauf que l'arc est tracé dans le sens des aiguilles d'une montre.
    X elliptical­quatrantx (x y) + Dessine un quart d'ellipse du point courant au point (x;y), avec le segment initial tangent à l'axe X (horizontal). Les coordonnées suivantes sont utilisées pour tracer des quarts d'ellipse avec leur segment initial alternativement tangent à l'axe Y et l'axe X.
    Y elliptical­quatranty (x y) + Dessine un quart d'ellipse du point courant au point (x;y), avec le segment initial tangent à l'axe Y (vertical). Les coordonnées suivantes sont utilisées pour tracer des quarts d'ellipse avec leur segment initial alternativement tangent à l'axe X et l'axe Y.
    Z closepath aucun Ferme le sous-chemin courant en traçant une ligne droite du point courant au point initial du sous-chemin.

    Les points de collage

    Les formes peuvent disposer de points de collage afin d'accrocher à un endroit précis de la forme un connecteur. Par défaut, quatre points de collage sont définis au milieu de chaque côté du rectangle défini par la svg:viewBox. Pour définir des points de collage supplémentaires, il suffit d'ajouter l'attribut draw:glue-points dans la balise draw:enhanced-geometry et donner les coordonnées (x;y) de ces points :

    <draw:enhanced-geometry 
       svg:viewBox="0 0 6 9" 
       draw:type="non-primitive" 
       draw:enhanced-path="M 0 0 Q 3 18 6 0" 
       draw:glue-points="0 0 1 5 2 8 4 8 5 5 6 0"
     />

    Dans l'exemple précédent, des points de collage ont été positionnés sur la courbe pour les nombres entiers : (-3;9) (-2;4) (-1;1) (le point 0;0 existe déjà) (1;1) (2;4) et (3;9). Pour visualiser ces points, dans LibreOffice sélectionnez un connecteur dans la barre d'outils Dessin et approchez la souris de la forme comme sur la figure ci-dessous.

    Points de collage de la forme

    Il existe cependant une limitation : les points de collage ne peuvent pas sortir de la zone définie par svg:viewBox.

    Les poignées

    Objectif

    Certaines formes disposent de poignées, sous l'aspect de ronds jaunes, qui permettent de déformer la forme, par exemple le sourire gai/triste de la frimousse. Nous allons voir comment en gérer une pour une forme très simple : un triangle dont le côté gauche est vertical et le sommet opposé sur le côté droit sera mobile verticalement à l'aide d'une poignée. Une forme peut cependant comporter plusieurs poignées.

    Le triangle est dessiné dans un patron de 10x10. Les coordonnées fixées de ses trois angles sont (0;0), (10;6) et (0;10) comme sur cette figure :

    Triangle avec un côté vertical

    Tracé sans la poignée

    En s'inspirant du codage XML du rectangle de la section Le code XML ci-dessus, on obtient le code suivant :

    <draw:enhanced-geometry
         svg:viewBox="0 0 10 10"
         draw:type="non-primitive"
         draw:enhanced-path="M 0 0 L 10 6 0 10 Z"
     />

    Veuillez noter que le draw:enhanced-path se termine par la commande Z. Pourquoi ne pas relier au point de départ (0;0) à l'aide d'un point supplémentaire ? L'utilisation d'une commande L ne fermerait pas la figure en polygone, mais formerait une polyligne de quatre points, dont le dernier point tomberait par accident sur le premier. Il ne serait pas possible d'y appliquer un remplissage par exemple. La commande Z permet donc de former un polygone avec trois points.

    Création de la poignée

    La poignée peut être déplacée par cliquer-glisser sur le cercle jaune. Ses coordonnées sont variables. La forme a donc besoin de disposer de ces valeurs variables. Cela s'obtient à l'aide de l'attribut draw:modifiers de l'élément draw:enhanced-geometry, qui contient une liste de valeurs, en général une par poignée car une poignée n'a en général qu'un degré de liberté. Si la poignée a ses deux degrés de liberté, alors il faut prévoir deux valeurs. La valeur indiquée dans le code XML correspond à la valeur initiale, mais elle sera modifiée dès que l'on déplacera la poignée.

    <draw:enhanced-geometry ... draw:modifiers="6" />

    La poignée elle-même est constituée d'un élément draw:handle, un sous-élément de l'élément draw:enhanced-geometry. Ce sous-élément dispose d'un attribut draw:handle-position avec les coordonnées x et y de la poignée. Pour que la poignée se déplace verticalement sur le côté droit, la valeur de x est fixée à 10, alors que la valeur y doit prendre la position de la poignée. Cette position est récupérée à l'aide d'une référence, codée avec le caratère $ suivi par un entier correspondant au numéro de la poignée suivant l'ordre de l'attribut draw:modifiers. La numérotation commence à 0. Le code est donc le suivant :

    <draw:enhanced-geometry
            svg:viewBox="0 0 10 10" draw:type="non-primitive"
            draw:modifiers="6"
            draw:enhanced-path="M 0 0 L 10 6 0 10 Z" >
         <draw:handle draw:handle-position="10 $0" />
     </draw:enhanced-geometry>

    Notez que l'élément draw:handle n'a pas de sous-élément, et peut donc utiliser une balise combinée début-fin, alors que l'élément draw:enhanced-geometry a maintenant un sous-élément et nécessite alors une balise de fin séparée.

    Utilisation de la poignée

    Vous pouvez enregistrer le fichier et observer le comportement de la poignée dans LibreOffice : le triangle n'a pas changé, une poignée est apparue à son sommet droit ; vous pouvez déplacer la poignée verticalement, mais le sommet ne suit pas la poignée pour le moment. Il suffit de remplacer l'ordonnée de ce point par la référence à la valeur de la poignée avec la même syntaxe :

    draw:enhanced-path="M 0 0 L 10 $0 0 10 Z"
    

    Le code final est donc :

    <draw:enhanced-geometry
         svg:viewBox="0 0 10 10"
         draw:type="non-primitive"
         draw:modifiers="6"      
         draw:enhanced-path="M 0 0 L 10 $0 0 10 Z" >
         <draw:handle draw:handle-position="10 $0"  />
    </draw:enhanced-geometry>

    Vous pouvez enregistrer le fichier et jouer avec la poignée : le triangle se déforme mais conserve sa pointe sur la verticale.

    Triangle déformé par la poignée

    Limitation de la plage de la poignée

    Vous remarquerez que vous pouvez même sortir de la zone définie par le patron du début svg:viewBox. Si vous souhaitez l'empêcher, vous pouvez fixer des valeurs minimales et maximales à la référence. Ajoutez les attributs draw:handle-range-x-minimum et draw:handle-range-x-maximum ou draw:handle-range-y-minimum et draw:handle-range-y-maximum au sous-élément draw:handle-position. Le code devient :

    <draw:enhanced-geometry
         svg:viewBox="0 0 10 10"
         draw:type="non-primitive"
         draw:modifiers="6"      
         draw:enhanced-path="M 0 0 L 10 $0 0 10 Z" >
         <draw:handle draw:handle-position="10 $0" draw:handle-range-y-minimum="0" draw:handle-range-y-maximum="10"/>
    </draw:enhanced-geometry>

    Ainsi la poignée se retrouve bloquée à l'intérieur de la zone définie par svg:viewBox.

    Application au point de collage

    Un point de collage peut se déplacer avec la poignée, ou même être confondu avec la poignée. Il suffit d'utiliser la référence à la valeur de la poignée dans les coordonnées du point de collage :

    draw:glue-points="10 $0"
    

    Ce qui donne le code :

    <draw:enhanced-geometry
         svg:viewBox="0 0 10 10" draw:type="non-primitive" draw:modifiers="6"      
         draw:glue-points="10 $0"
         draw:enhanced-path="M 0 0 L 10 $0 0 10 Z" >
         <draw:handle draw:handle-position="10 $0" draw:handle-range-y-minimum="0" draw:handle-range-y-maximum="10"/>
    </draw:enhanced-geometry>

    Notez que contrairement à la poignée ou au tracé du polygone, les points de collage ne peuvent pas sortir de la zone définie par svg:viewBox (voir tdf#68327).

    Les formules

    Premier essai

    Cet exemple va vous montrer comment utiliser des formules pour calculer les coordonnées des points de votre forme. En particulier lorsque vous utilisez une poignée, la forme se déforme et certains points doivent être recalculés en fonction de la position de la poignée. Nous allons utiliser l'exemple du parallélogramme qui a un côté gauche vertical fixe et le côté opposé qui sera déplaçable verticalement, comme sur cette figure :

    Parallélogramme à côté droit modifiable par la poignée

    Le système de coordonnées choisi reste dimensionné à 10x10. En repartant de l'exemple du triangle ci-dessus, ce n'est pas très difficile à construire, sauf en ce qui concerne le coin inférieur droit. Un premier essai pourrait ressembler à :

    <draw:enhanced-geometry
        svg:viewBox="0 0 10 10"
        draw:type="non-primitive"
        draw:modifiers="3"
        draw:enhanced-path="M 0 0 L 10 $0  10 $0+10  0 10 Z">
          <draw:handle draw:handle-position="10 $0"  />
     </draw:enhanced-geometry>

    Cependant ce tracé ne fonctionne pas, car il contient $0+10 dans le chemin qui n'est pas reconnu : il n'est pas possible d'utiliser une expression comme paramètre d'une commande. Un nouvel élément est nécessaire, ce sera l'élément draw:equation.

    L'élément draw:equation

    L'élément draw:equation est un sous-élément de draw:enhanced-geometry. Il contient deux attributs : draw:name et draw:formula. Il ne contient pas de sous-élément et est donc combiné dans une balise début-fin :

    <draw:equation draw:name="..." draw:formula="..." />
    

    Le nom de la formule est utilisé pour faire référence à la valeur. La spécification d'ODF permet de choisir n'importe quel nom arbitraire, mais LibreOffice convertira systématiquement les noms en f0 f1 f2 etc. Pour identifier vos formules, il est donc plus facile d'utiliser dès le début ces noms.

    L'expression de la formule est indiquée dans l'attribut draw:formula. En plus des opérateurs arithmétiques +, -, *, /, vous pouvez utilisez quelques fonctions (par exemple sqrt pour la racine carrée (square root)) et quelques constantes (comme pi). Vous en trouverez une liste complète au chapitre 19.171 draw:formula des spécifications ou dans le tableau ci-dessous.

    Application à l'exemple

    Pour revenir à notre exemple, la formule est donc $0+10 et se code ainsi :

    <draw:equation draw:name="f0" draw:formula="$0+10" />
    

    Dans l'expression du chemin, il faut utiliser une référence à cette formule à l'aide du caractère ? immédiatement suivi du nom de l'équation. Le chemin devient :

    draw:enhanced-path="M 0 0 L 10 $0 10 ?f0 0 10 Z"
    

    L'ensemble de l'élément enhanced-geometry s'écrit :

    <draw:enhanced-geometry
         svg:viewBox="0 0 10 10"
         draw:type="non-primitive"
         draw:modifiers="3"
         draw:enhanced-path="M 0 0 L 10 $0 10 ?f0 0 10 Z">
           <draw:equation draw:name="f0" draw:formula="$0+10" />
           <draw:handle draw:handle-position="10 $0" />
     </draw:enhanced-geometry>

    Liste des fonctions utilisables dans une formule

    La liste fournie par les spécifications est donnée dans le tableau suivant.

    Fonction Description
    abs(n) Renvoie la valeur absolue de n
    sqrt(n) Renvoie la racine carrée positive de n
    sin(n) Renvoie le sinus trigonométrique de n, où n est l'angle spécifié en radians
    cos(n) Renvoie le cosinus trigonométrique de n, où n est l'angle spécifié en radians
    tan(n) Renvoie la tangente trigonométrique de n, où n est l'angle spécifié en radians
    atan(n) Renvoie l'arc tangente de n en radians.
    min(x,y) Renvoie la plus petite des deux valeurs
    max(x,y) Renvoie la plus grande des deux valeurs
    atan2(x,y) Renvoie l'angle en radians du vecteur (x,y) avec l'axe x horizontal
    if(c,x,y) Test de condition : si c est strictement supérieur à zéro, l'expression x est évaluée et renvoyée ; sinon l'expression y est évaluée et renvoyée.

    Note : la spécification ODF donne le degré comme unité d'angle mais LibreOffice utilise le radian.

    Bibliographie

    Quelques liens (en anglais) pour creuser la question :

    • Ce tutoriel est basé sur celui écrit par Regina Henschel pour AOO.
    • Eisenberg, J. David
    Creating Custom Shapes.2005.
    http://books.evc-cit.info/odbook/custom_shapes_article.odt [vérifié le 30 juin 2013]
    • OpenDocument-v1.2-part1
    Open Document Format for Office Applications (OpenDocument) Version 1.2
    Part1: OpenDocument Schema. 29 September 2011. OASIS Standard.
    http://docs.oasis-open.org/office/v1.2/os/OpenDocument-v1.2-os-part1.html.
    • W3C SVG Working Group
    SVG 1.1 Second Edition Recommendation. 16 August 2011.
    http://www.w3.org/TR/SVG/Overview.html