Composants et API JavaScript
Cette page couvre la surface JavaScript/TypeScript de la liaison React : le
composant <DataFlowPlayer> et ses props, l'enregistrement d'icônes, et la
coloration syntaxique. Pour la forme de la spécification JSON (spec), voir la
Référence API (spec JSON).
Les mêmes options existent dans les trois autres paquets —
<dataflow-player> (élément personnalisé), <dfa-player> (Angular) et
mountPlayer (le cœur, sans framework). Le tableau de props ci-dessous fait
référence pour tous ; seule la façon de les passer change. Voir
Paquets et liaisons.
import { DataFlowPlayer } from '@dataflow-animator/react';
import '@dataflow-animator/core/styles.css';
<DataFlowPlayer>
Le composant qui compile une spec et l'affiche dans un lecteur multimédia.
Seule la prop spec est requise.
| Prop | Type | Défaut | Rôle |
|---|---|---|---|
spec | DataFlowSpec | — (requis) | La spécification à animer. |
height | number | string | 420 | Hauteur de la scène (ex. 420, '60vh'). |
controls | boolean | true | Affiche la barre de lecture et la navigation par étapes. |
exportable | boolean | false | Ajoute un bouton qui ouvre la spec JSON (copie / téléchargement). |
videoExport | boolean | VideoExportConfig | false | Ajoute un bouton qui exporte l'animation en fichier WebM, MP4 ou GIF. |
autoPlay | boolean | false | Démarre la lecture automatiquement. |
loop | boolean | false | Rejoue en boucle à la fin. |
speed | number | 1 | Vitesse de lecture (1 = normal). |
theme | PlayerTheme | 'default' | Palette visuelle (voir plus bas). |
mode | 'light' | 'dark' | 'auto' | 'auto' | Variante de theme à afficher. |
density | 'compact' | 'comfortable' | 'spacious' | 'comfortable' | Densité visuelle (taille des éléments / espacement). |
width | number | string | conteneur | Largeur de la scène. Lue au montage, avant la première mesure. |
initialT | number | 0 | Instant d'ouverture du player, en ms. Lu une seule fois. |
debug | boolean | false | Overlay d'inspection de la timeline interne. |
highlight | Highlighter | Prism | Coloration syntaxique personnalisée (cf. plus bas). |
fallback | ReactNode | — | Rendu côté serveur et jusqu'au montage du player, à la place de l'indicateur de chargement. |
className | string | — | Classe CSS additionnelle sur le conteneur racine. |
style | CSSProperties | — | Styles inline sur le conteneur racine. |
labels | Partial<PlayerLabels> | anglais | Localise le chrome du player (voir plus bas). |
Le player lit ses options une seule fois, à son montage : changer l'une d'elles —
spec comprise — le reconstruit. L'instant courant et l'état de lecture sont
repris, de sorte que scruber ou éditer une spec en direct reste fluide.
Le remontage est déclenché par la structure de la spec, pas par son identité référentielle : un objet littéral reconstruit à chaque rendu du parent coûte une sérialisation, pas une reconstruction. Le mémoïser reste utile sur un chemin de rendu chaud, mais ce n'est plus la différence entre fluide et saccadé.
Seul le premier montage honore initialT et autoPlay : tout remontage
suivant reprend à l'instant et à l'état de lecture courants, ce qui rend
invisible le fait de changer une option en cours de scrub.
Le premier montage est aussi le seul à attendre un affichage (deux frames), afin que l'emplacement — et son indicateur de chargement — soit réellement à l'écran avant que la spec ne soit compilée et mesurée. Un remontage, lui, est immédiat : le player précédent est encore là, et l'échanger contre deux frames de boîte vide serait un clignotement.
// très bien — une spec équivalente ne remonte rien
<DataFlowPlayer spec={{ nodes: [...], timeline: [...] }} />
// encore moins cher sur un parent qui se rend souvent
const spec = useMemo(() => ({ nodes: [...], timeline: [...] }), []);
<DataFlowPlayer spec={spec} />
Pour le rendu SSR / le placeholder d'hydratation et l'intégration Next.js / Docusaurus, voir Installation.
Thèmes
L'apparence du lecteur relève de deux choix indépendants :
theme— la palette (default,dots,blueprint,pcb,chalk,terminal,paper,neon) ;mode— la variante de cette palette à afficher (light,dark,auto).
Chaque thème possède une variante claire et une variante sombre : changer un axe
n'impose donc jamais l'autre. mode="auto" (la valeur par défaut) suit le site
hôte dès qu'un ancêtre porte data-theme="light|dark" (la convention
Docusaurus), et la préférence système sinon — la résolution est purement CSS,
donc compatible SSR et sans JavaScript.
// Un tableau noir qui suit quand même la préférence claire/sombre du lecteur.
<DataFlowPlayer spec={spec} theme="chalk" mode="auto" />
// Un circuit imprimé figé sur sa variante sombre, quoi que fasse l'hôte.
<DataFlowPlayer spec={spec} theme="pcb" mode="dark" />
Si vous stylez le lecteur vous-même, notez que l'élément racine porte
data-theme (la palette) et data-mode (la variante claire/sombre) : votre
propre CSS peut donc s'accrocher indépendamment à chacun des deux axes.
- default
- dots
- blueprint
- pcb
- chalk
- terminal
- paper
- neon
Basculez l'interrupteur clair/sombre de ce site pour voir l'autre variante du
thème sélectionné — les lecteurs ci-dessus sont tous en mode="auto".
pcb et schémas électriquesAvec direction: 'circuit', les fils sont teintés par leur net (le signal
qui les pilote), ce qui prime volontairement sur la couleur de flèche de la
palette : cette couleur porte du sens. Le thème pcb habille malgré tout la
carte, les composants et les libellés autour.
Chaque palette est un jeu de variables CSS --rdfa-* scopées sous
.rdfa-player. Pour en ajuster une, surchargez les variables sur votre propre
conteneur plutôt que de forker la feuille de style :
.my-diagram .rdfa-player {
--rdfa-accent: light-dark(#b91c1c, #f87171);
}
Exporter la spec (exportable)
Avec exportable, un bouton apparaît dans la barre de contrôles ; il ouvre la
spécification JSON (colorée) dans une fenêtre, avec deux actions :
- Copier dans le presse-papier ;
- Télécharger en fichier
.json.
<DataFlowPlayer spec={spec} exportable />
La copie et le téléchargement sont des opérations côté navigateur
(navigator.clipboard, ancre de téléchargement) : sans effet pendant le SSR, la
fenêtre ne s'ouvre qu'après hydratation. Sans effet si controls est false.
Exporter une vidéo (videoExport)
Avec videoExport, un second bouton apparaît dans la barre de contrôles. Il
ouvre un petit panneau — format, résolution, cadence — et écrit l'animation dans
un fichier.
<DataFlowPlayer spec={spec} videoExport />
Passez un objet pour restreindre ce que le panneau propose :
<DataFlowPlayer
spec={spec}
videoExport={{ formats: ['mp4'], resolutions: [1080], frameRates: [30] }}
/>
| Champ | Type | Défaut | Rôle |
|---|---|---|---|
formats | VideoExportFormat[] | les trois | Les formats proposés par le panneau, dans l'ordre. |
resolutions | number[] | [360, 540, 720, 1080] | Les hauteurs de sortie proposées, en pixels — 720 s'affiche 720p. |
frameRates | number[] | [15, 20, 24, 30, 60] | Les cadences proposées. |
bitrate | number | 4_000_000 | Débit vidéo. Ignoré par le GIF. |
filename | string | 'dataflow' | Nom de base du fichier, extension exclue. |
Une liste à une seule entrée cesse d'être une question : le réglage est
alors affiché en texte plutôt qu'en menu déroulant, donc la valeur reste
visible sans être modifiable. { formats: ['mp4'], resolutions: [1080] } fige
ainsi la sortie et ne laisse que la cadence à choisir.
Le panneau estime avant de s'engager
Les trois réglages interagissent, donc le panneau affiche la durée que prendra l'export et la met à jour à chaque changement. C'est cette estimation qui rend les réglages utiles : sur une même animation de 30 secondes, le WebM 720p annonce environ 8 s là où le GIF 1080p60 annonce environ 1 min 40 s — une différence qu'il vaut mieux voir avant d'appuyer qu'après.
La première estimation vient d'un modèle de coût mesuré, et les deux familles de format ne se comportent pas du tout pareil : la vidéo est presque insensible à la résolution (le travail consiste à rastériser le DOM une fois, puis à encoder en matériel), tandis que le GIF est linéaire en pixels (la quantification et le LZW tournent en JavaScript). Après un premier export, le lecteur utilise ce que la machine a réellement fait plutôt que le modèle : les estimations suivantes sont plus justes.
La lecture n'est pas interrompue
L'export monte un second lecteur hors écran et le parcourt en temps virtuel
via clock.seek. Le lecteur affiché continue de jouer, à sa vitesse, pendant
que le fichier s'écrit — et l'export n'attend jamais le temps réel : il se
termine en une fraction de la durée de l'animation (de l'ordre du dixième au
tiers sur les démos de ce site). Une barre de progression et un bouton
Annuler occupent le menu pendant l'opération.
Choisir un format
- WebM est le plus rapide et le plus léger. Il se lit dans Chrome, Firefox et Edge — mais pas dans Safari, ni dans PowerPoint.
- MP4 se lit partout : Safari, présentations, réseaux sociaux, messageries. C'est le format à choisir dès que le fichier est destiné à quelqu'un d'autre.
- GIF s'anime là où une vidéo ne le fait pas — un README GitHub, un fichier Markdown. Il utilise par défaut une image plus petite et une cadence plus basse, comme le veut l'usage du format. Ces diagrammes sont en aplats : la palette de 256 couleurs ne coûte rien de visible.
L'export requiert l'API WebCodecs pour le WebM et le MP4 (Chromium, Firefox
et Safari récent) ; le GIF s'en passe. Les encodeurs sont chargés à la
demande : un lecteur qui n'exporte jamais ne télécharge rien de ce code. Sans
effet si controls vaut false.
Localiser le chrome (labels)
La barre de contrôles et la fenêtre JSON portent des chaînes visibles — les
aria-label et title (infobulles) des boutons, le titre de la fenêtre — en
anglais par défaut. La prop labels les remplace clé par clé ; toute clé
omise garde sa valeur anglaise :
<DataFlowPlayer
spec={spec}
exportable
labels={{
play: 'Lecture',
pause: 'Pause',
prevStep: 'Étape précédente',
nextStep: 'Étape suivante',
jsonSpec: 'Spécification JSON',
}}
/>
La liste complète des clés est le type exporté PlayerLabels : restart,
play, pause, prevStep, nextStep, progressBar, fullscreen,
exitFullscreen, jsonSpec, download, copy, copied, copyToClipboard,
close, closeDialog, loading.
loading est l'intruse : elle n'appartient pas au chrome mais à
l'emplacement que le player affiche avant son montage, et qui révèle un
indicateur de chargement quand l'attente dure assez longtemps pour mériter
d'être signalée — voir
SSR et hydratation. Elle vit ici pour
la même raison que les autres : que la valeur par défaut reste dans le cœur
plutôt que dans chaque liaison.
Ces chaînes vivent dans des attributs lus par les infobulles et les
technologies d'assistance — aucune n'est dessinée sur la scène. Ce site passe
labels sur chaque player qu'il rend : c'est ce qui fait suivre au chrome la
langue de la page, y compris celle-ci.
Icônes personnalisées
Le champ icon d'un nœud résout
d'abord une techno connue, puis un badge enregistré. Deux fonctions
alimentent ces registres :
type IconSource = string | (() => SVGElement);
registerNodeIcon(type: string, icon: IconSource): void; // pictogramme principal du nœud
registerSubIcon(name: string, icon: IconSource): void; // badge `icon` (techno)
Une icône est du balisage SVG, ou une fabrique renvoyant un SVGElement
quand elle doit varier :
import { registerSubIcon } from '@dataflow-animator/react';
registerSubIcon(
'k8s',
'<svg viewBox="0 0 24 24" fill="#326CE5"><path d="…" /></svg>'
);
// puis : { id: 'orchestrator', type: 'cloud', icon: 'k8s' }
// une fabrique, appelée à chaque résolution
registerSubIcon('build', () => buildAnimatedGlyph());
Le balisage est analysé une seule fois, à la première utilisation, puis cloné.
Un enregistrement l'emporte toujours sur l'icône intégrée de même nom — y compris
sur les pictogrammes à état switch et push_button.
registerNodeIcon / registerSubIcon mutent un registre au niveau module,
partagé entre toutes les instances du player et entre les requêtes en
environnement SSR. Appelez-les une seule fois au démarrage de l'application
(fichier d'entrée, _app.tsx, layout.tsx…), jamais dans un corps de composant
ou un useEffect. L'enregistrement ne touche jamais au DOM : il est donc sûr au
niveau module, y compris dans un bundle qui tourne aussi côté serveur.
Les lecteurs getNodeIcon(type) / getSubIcon(name) permettent d'inspecter le
registre si besoin ; tous deux renvoient un SVGElement neuf.
Coloration syntaxique
Par défaut, le code (set_content en mode code, corps de paquets) est coloré
par Prism, via la fonction exportée highlightCode :
highlightCode: (code: string, language: string) => string; // type Highlighter
Vous pouvez la remplacer entièrement par la prop highlight — utile pour
brancher Shiki, Highlight.js, ou éviter d'embarquer Prism :
const myHighlighter: Highlighter = (code, language) =>
myEngine.toHtml(code, language);
<DataFlowPlayer spec={spec} highlight={myHighlighter} />;
La fonction reçoit le code brut et le language déclaré, et renvoie du HTML.
escapeHtml est aussi exporté pour un repli sans coloration.
API avancée (moteur)
Pour des intégrations sur mesure (rendu maison, tests, outillage), le moteur pur est exporté. Sa surface est bas niveau et peut évoluer plus librement que le composant :
| Export | Rôle |
|---|---|
compile(spec) | Compile une spec en Timeline (clips ordonnés). |
evaluate(timeline, t) | État visuel pur à l'instant t (ms). |
stepIndexAt / nextStop / prevStop | Navigation par étapes et points d'arrêt. |
computeLayout(spec) | Positions relatives des nœuds (ratios), sans DOM. |
Ces fonctions ne touchent aucun DOM et peuvent s'exécuter côté serveur.
L'horloge du player n'est pas un hook React : elle vit dans le cœur sous le nom
createPlayerClock, exporté pour les hôtes qui pilotent mountStage eux-mêmes.