Contrôles utilisateur
Contrôles utilisateur
Section intitulée « Contrôles utilisateur »Imaginons maintenant que ayons besoin d’un contrôle qui n’existe pas dans X4. Mettons une gauge: Un cercle qui va afficher un pourcentage et un chiffre au centre.
Pour cela, le plus simple est de dériver du SVGComponent. Nous pourrons dessiner le cercle, le pourcentage et le texte directement en SVG.
Voyons voir, d’abord nous dérivons simplement de SVGComponent, nous déclarons nos membres de travail et enfin nous allons dessiner le contrôle.
import {SVGComponent} from "x4js";
class MyGauge extends SVGComponent { private m_percent: number; // between 0 and 1
constructor( props ) { super( props ); this.m_percent = props.percent; this.mkSVGPath( this.m_percent ); }
// construct the svgpath, we will use SVGPathBuilder mkSVGPath( percent: number ) { const builder = new SVGPathBuilder( );
// we will render in a 'virtual' rect of 100x100 // the we will let svg render into the correct destination // rectangle
// 1. background circle builder.path( ) .arc( 50, 50, 50, 0, 360 ) .fill( "transparent" ) .stroke( "gray", 5 );
// 2. percent circle builder.path( ) .arc( 50, 50, 50, 0, percent*360 ) .fill( "transparent" ) .stroke( "red", 5 );
// 3. text builder.text( 50, 50, Math.round(percent*100)+"%" ) .fontSize( 25 ) .textAlign( "center" ) .verticalAlign( "center" ) .fill( "black" )
// 4. make this drawing our content // we tell svg that the virtual rect is 0, 0, 100, 100 this.setSVG( 0, 0, 100, 100, builder ); }}Et voilà notre gauge fonctionne. Nous pouvons simplement l’utiliser comme ceci:
new MyGauge( { percent: 0.5} );Remarque: l’argument du constructeur est un objet, Typescript va analyser qu’il s’agit d’un objet de type SVGProp, argument par défaut d’un composant SVGComponent. Il n’est pas typé et votre éditeur préféré ne va pas vous proposer le membre percent vu qu’il ne le connait pas.
Pour résoudre ceci, nous avons 2 solutions:
- ajouter un paramètre au constructeur qui est le pourcentage. Le fonctionnement standard de x4 ne recommande pas ceci.
- typer le paramètre du constructeur Ce que nous allons privilégier.
Comme nous allons changer le paramètre reçu, X4 va faire un certain nombre de choses pour vous:
- il va garder ce qui a été reçu (props) dans un membre qui s’appelle
m_props. - il va permettre a l’éditeur de connaître ce paramètre.
Voici la nouvelle définition de MyGauge (nous ignorons la partie de dessin qui ne change pas):
import {SVGComponent,SVGProps} from "x4js";
// new propertiesinterface MyGaugeProps extends SVGProps { percent: number; // between 0 and 1}
// we let x4 known about our propsclass MyGauge extends SVGComponent<MyGaugeProps> { constructor( props: MyGaugeProps ) { super( props ); this.mkSVGPath( this.m_props.percent ); }
// mkPath( ) { // }}Emettre un évènement
Section intitulée « Emettre un évènement »Maintenant l’objectif est de générer un évènement lorsque l’utilisateur tourne la molette de sa souris au dessus de notre gauge afin de modifier le pourcentage affiché.
Le premier point est de capter l’évènement wheel en provenance du browser, pour cela nous allons demander a x4 de lier cet évènement à une méthode que nous créons:
constructor( props: MyGaugeProps ) { super( props ); this.mkSVGPath( this.m_props.percent );
// we 'capture' wheel event this.setDomEvent( "wheel", e => this.onWheel( e ) );}
onWheel( e: MouseWheelEvent ) { ...}Ensuite, il va falloir émettre notre évènement: (nous ne rentrerons pas deans le détail de l’évènement wheel du dom, pour cela vous pouvez consulter mdn)
onWheel( e: WheelEvent ) { // we transform the dom 'wheel' event in an X4 'wheel' event this.emit( 'wheel', EvMessage('wheel',e.deltaY) );}Pour résoudre ce problème, nous allons dire à typescript que notre composant va être source d’évènements de type wheel.
Modifions simplement les définitions qui suivent:
// new event mapinterface MyGaugeEventMap extends CEventMap { wheel: EvMessage; // we will fire events named wheel with a EvMessage parameter}
// new propertiesinterface MyGaugeProps extends SVGProps<MyGaugeEventMap> { percent: number; // between 0 and 1}
// we let x4 known about our props AND event mapclass MyGauge extends SVGComponent<MyGaugeProps,MyGaugeEventMap> { ...}Et voilà, typescript est content, l’éditeur aussi car il nous propose de gérer l’évènement wheel, donc nous aussi.
Dernier point, après vous allez pouvoir boire un café bien mérité.
Nous pouvons créer notre nouveau composant
new MyGauge( { percent: 0.5, events: { wheel: e => this.onWheel( e ) }} );En soit c’est bien mais j’aimerais que ce soit plus simple:
new MyGauge( { percent: 0.5, wheel: e => this.onWheel( e )} );Comment réaliser ceci ?
// new event mapinterface MyGaugeEventMap extends CEventMap { wheel: EvMessage; // we will fire events named wheel with a EvMessage parameter}
// new propertiesinterface MyGaugeProps extends SVGProps<MyGaugeEventMap> { percent: number; // between 0 and 1 wheel: EvHandler<EvMessage>; // HERE}
// we let x4 known about our props AND event mapclass MyGauge extends SVGComponent<MyGaugeProps,MyGaugeEventMap> { constructor( props: MyGaugeProps ) { super( props );
// AND HERE this.mapPropEvents( props, "wheel" );
... }}