Aller au contenu

Contrôles utilisateur

Quand aucun contrôle fourni ne convient, vous écrivez le vôtre. L’exemple de ce chapitre est une jauge circulaire qui affiche un pourcentage, dessinée en SVG.

On dérive SvgComponent, le composant SVG de base, et on construit le dessin avec SvgBuilder.

import { SvgBuilder, SvgComponent, SvgProps } from 'x4js';
interface MyGaugeProps extends SvgProps {
percent: number;
}
class MyGauge extends SvgComponent<MyGaugeProps> {
constructor( props: MyGaugeProps ) {
// le dessin est fait dans un repère de 100 x 100
super( { ...props, viewbox: "0 0 100 100" } );
this.setPercent( props.percent );
}
setPercent( percent: number ) {
const svg = new SvgBuilder( );
// le fond de la jauge
svg.circle( 50, 50, 45 ).no_fill( ).stroke( "lightgray", 5 );
// l'arc de la valeur
svg.path( ).arc( 50, 50, 45, 0, percent*360 ).no_fill( ).stroke( "red", 5 );
// le texte au centre
svg.text( 50, 50, Math.round( percent*100 )+"%" )
.fontSize( 25 )
.textAlign( "center" )
.verticalAlign( "center" );
this.setSvg( svg );
}
}

La jauge s’utilise comme n’importe quel composant :

const gauge = new MyGauge( { percent: 0.5, width: 120, height: 120 } );
// plus tard
gauge.setPercent( 0.75 );

Trois points à retenir :

  1. Les propriétés sont typées. L’interface MyGaugeProps étend celle du composant de base, et la classe la reçoit en paramètre de type. L’éditeur propose alors percent, et refuse une faute de frappe.
  2. Les propriétés sont passées telles quelles au parent. Elles restent disponibles ensuite dans this.props.
  3. Le composant se met à jour lui-même. setPercent redessine la jauge : c’est le développeur du composant qui décide quoi faire quand une valeur change.

Supposons que la jauge doive réagir à la molette de la souris. On branche un gestionnaire sur l’événement du navigateur avec addDOMEvent :

constructor( props: MyGaugeProps ) {
super( { ...props, viewbox: "0 0 100 100" } );
this.addDOMEvent( "wheel", ( ev ) => this.onWheel( ev ) );
this.setPercent( props.percent );
}
private onWheel( ev: WheelEvent ) {
// ...
}

addDOMEvent est réservé à l’écriture de contrôles. Sur un contrôle standard, on utilise ses propriétés et ses événements.

Le contrôle ne doit pas décider lui-même de ce que signifie la molette : il prévient celui qui l’utilise. On déclare l’événement, puis on l’émet avec fire.

import { ComponentEvent, ComponentEvents, EventCallback, SvgBuilder, SvgComponent, SvgProps } from 'x4js';
// ce que transporte l'événement
interface EvGaugeWheel extends ComponentEvent {
delta: number;
}
// les événements du contrôle
interface MyGaugeEvents extends ComponentEvents {
wheel: EvGaugeWheel;
}
interface MyGaugeProps extends SvgProps {
percent: number;
wheel?: EventCallback<EvGaugeWheel>; // forme courte, dans les propriétés
}
class MyGauge extends SvgComponent<MyGaugeProps,MyGaugeEvents> {
constructor( props: MyGaugeProps ) {
super( { ...props, viewbox: "0 0 100 100" } );
// branche le gestionnaire reçu dans les propriétés
this.mapPropEvents( props, "wheel" );
// transforme l'événement du navigateur en événement du contrôle
this.addDOMEvent( "wheel", ( ev ) => this.fire( "wheel", { delta: ev.deltaY } ) );
this.setPercent( props.percent );
}
// setPercent comme plus haut
}

Celui qui crée la jauge peut alors écrire, avec l’aide de l’éditeur :

const gauge = new MyGauge( {
percent: 0.5,
wheel: ( ev ) => console.log( ev.delta ),
});

ou s’abonner plus tard avec gauge.on( "wheel", … ).

Une classe CSS au nom du contrôle lui est associée automatiquement : ici mygauge. Mettez-y les couleurs et les tailles, de préférence sous forme de variables CSS, pour que le contrôle suive le thème de l’application. Voir Thèmes et CSS.

Dans l’exemple, les couleurs sont écrites dans le code pour rester court. Dans un vrai contrôle, donnez plutôt une classe à chaque élément du dessin avec addClass, et réglez les couleurs dans la feuille de style.

Pour qu’un contrôle de saisie soit pris en compte par un Form, il doit avoir un name et répondre à l’interface form-element, c’est-à-dire savoir donner sa valeur, la recevoir, et dire si elle est valide. Les contrôles fournis, comme Input ou Select, sont de bons modèles à lire dans les sources.