gestion_table_tournante_libre/src/interface/plan/PlanDessin.svelte

88 lines
3.3 KiB
Svelte
Raw Normal View History

<!-- © 2026 TechnoLibre (http://www.technolibre.ca)
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl) -->
<svelte:options namespace="svg" />
<script>
// Le dessin du plan (§ 7.1, § 7.3 à § 7.7), enfant du groupe <g data-vue>
// que Plan.svelte transforme : les motifs, les tables — plateaux, chaises,
// poignées, pastilles —, puis les listes de noms, peintes par-dessus et
// transparentes au pointeur. Le composant ne lit k qu'à travers le modèle
// (modele.js), qu'il reçoit entier ; aucun attribut qu'il écrit ne dépend
// de k hors du franchissement d'un seuil — régime des cibles, K_LISTES.
//
// Les mesures du texte se relèvent sur une sonde : un <text> caché au
// style des listes, et un tspan en italique pour les titres. La hauteur
// d'une ligne est la hauteur d'encre du gabarit (mesure_texte.js) ; les
// listes paraissent une fois les mesures prises, et la largeur de leur
// bloc est LARGEUR_BLOC_NOMS_CM du registre. Aucun <canvas>.
//
// Un plan monté caché — un ancêtre en display: none — n'a pas de mise en
// page : ses largeurs mesurées vaudraient 0. Les mesures ne se prennent
// donc que sur une sonde rendue, au montage, puis à chaque changement de
// taille du <svg> qui porte le dessin, qu'un ResizeObserver signale : un
// plan qui se cache perd ses mesures, et ses listes, et les reprend en se
// montrant.
import { untrack } from 'svelte';
import { constante } from '../../geometrie/constantes.js';
import { TAILLE_TEXTE_LISTE_CM } from '../../geometrie/texte.js';
import ListeNoms from './ListeNoms.svelte';
import { creerMesureur, hauteurLigne, mesurable } from './mesure_texte.js';
import Motifs from './Motifs.svelte';
import TablePlan from './TablePlan.svelte';
let { modele } = $props();
const prefixe = $props.id();
const largeur = constante('LARGEUR_BLOC_NOMS_CM');
let sonde = $state(null);
let sondeItalique = $state(null);
let mesures = $state(null);
// Prend les mesures quand la sonde est rendue et qu'il n'y en a pas ; les
// oublie quand elle ne l'est plus.
function actualiserMesures() {
if (!mesurable(sonde)) mesures = null;
else if (mesures === null) {
mesures = { hauteur: hauteurLigne(sonde), mesurer: creerMesureur(sonde), mesurerItalique: creerMesureur(sondeItalique) };
}
}
$effect(() => {
const cible = sonde.ownerSVGElement ?? sonde;
untrack(actualiserMesures);
const observateur = new ResizeObserver(actualiserMesures);
observateur.observe(cible);
return () => observateur.disconnect();
});
</script>
<Motifs {prefixe} />
{#each modele.tables as table (table.id)}
<TablePlan {table} signaler={modele.signalerConflits} {prefixe} />
{/each}
<text class="sonde" font-size={TAILLE_TEXTE_LISTE_CM} aria-hidden="true" bind:this={sonde}
><tspan class="titre" bind:this={sondeItalique}></tspan></text
>
{#if modele.listesRendues && mesures !== null}
{#each modele.tables as table (table.id)}
<ListeNoms {table} {mesures} {largeur} />
{/each}
{/if}
<style>
/* La sonde a le style des listes (ListeNoms.svelte) ; elle ne se voit pas
et ne porte de texte que le temps d'une mesure. */
.sonde {
font-family: var(--police-interface);
white-space: pre;
visibility: hidden;
pointer-events: none;
}
.titre {
font-style: italic;
}
</style>