Faire de la géométrie réelle dans le navigateur avec Geometric.js
Geometric.js apporte l intersection de polygones, les boîtes englobantes, le test point dans polygone et l interpolation de trajectoire aux cartes, graphiques, SVG et Canvas.
Geometric.js est une bibliothèque de géométrie 2D dans laquelle chaque primitive est un simple tableau JavaScript : un point est [x, y], une ligne est [[x, y], [x, y]], et un polygone est un tableau de points — ainsi, la valeur que vous calculez est la même que celle que vous sérialisez en JSON et que vous dessinez en SVG ou sur Canvas.
Quiconque développe des graphiques ou des cartes interactives a déjà ressenti la friction que représente le besoin d’une seule petite opération géométrique, obligeant à réinventer les calculs mathématiques à chaque fois. Si vous avez déjà implémenté manuellement le lancer de rayon pour des tests de point dans un polygone, ou copié-collé des calculs de boîte englobante dans un graphique D3, Geometric.js remplace ces fragments de code par des fonctions nommées et testées qui opèrent directement sur les tableaux que vous possédez déjà. Ce tour d’horizon couvre trois fonctionnalités phares (intersection de polygones, boîtes englobantes et interpolation), puis deux cas d’usage où recourir à la bibliothèque est bien plus avantageux qu’écrire la trigonométrie soi-même.
Points clés
- Geometric.js représente un point sous la forme
[x, y], une ligne comme deux points, et un polygone comme un tableau de points — aucune classe à instancier et rien à adapter avant de dessiner en SVG ou sur Canvas. pointInPolygon(point, polygon)retourne un booléen en utilisant le lancer de rayon, vous offrant un test de détection de clic sur Canvas en un seul appel, sans calcul géométrique externe.polygonBounds(polygon)retourne[topLeft, bottomRight]sous forme de deux points[x, y], ounullpour moins de trois sommets — suffisant pour positionner une info-bulle autour de n’importe quelle forme.- Les opérations booléennes retournant une géométrie —
polygonIntersection,polygonUnion,polygonDifferenceetpolygonXor— nécessitent geometric v3 ou ultérieur ; le prédicatpolygonIntersectsPolygonest disponible depuis la v2. - À partir de la version 3.x, geometric intègre ses propres déclarations TypeScript, ce qui vous permet d’installer
geometricsans avoir à installer@types/geometric.
Les primitives sont de simples tableaux, et c’est tout l’intérêt
Ce qui rend Geometric.js agréable à utiliser, c’est qu’il n’introduit aucune structure de données. Un point est un tableau [x, y], une ligne est un tableau de deux points, et un polygone est un tableau de sommets. Il n’y a aucune classe personnalisée à instancier ni aucune structure de données particulière à apprendre, ce qui signifie que les valeurs que vous transmettez sont les mêmes que celles que vous pouvez sérialiser, inspecter et dessiner. Comme la sortie est un tableau, elle s’intègre directement dans D3, un attribut SVG points, ou une boucle Canvas ctx.lineTo sans aucun code adaptateur :
import { polygonRegular } from "geometric";
const pentagon = polygonRegular(5, 10000, [150, 150]);
// pentagon est [[x, y], [x, y], ...] — dessinez-le directement :
// SVG
polygon.setAttribute("points", pentagon.map(p => p.join(",")).join(" "));
// Canvas
ctx.beginPath();
pentagon.forEach(([x, y], i) => (i ? ctx.lineTo(x, y) : ctx.moveTo(x, y)));
ctx.closePath();
Cet aller-retour (calcul, sérialisation et rendu, tous sur le même tableau) est ce que le README entend par « garder la géométrie simple ».
Installation et importation
Discover how at OpenReplay.com.
Installez geometric depuis npm, pnpm ou yarn ; il est distribué en tant que package ESM-first avec prise en charge de CommonJS et des déclarations TypeScript intégrées. La dernière version sur npm est la 3.0.9 (juillet 2026).
npm i geometric
# ou : pnpm add geometric
# ou : yarn add geometric
import { pointInPolygon, polygonBounds } from "geometric"; // ESM
const geometric = require("geometric"); // CommonJS
Deux remarques concernant la configuration. Premièrement, les déclarations TypeScript sont générées à partir du code source et publiées avec le package, vous ne devez donc pas installer @types/geometric. Ce package DefinitelyTyped est figé à la version 2.5.3 et est redondant avec la v3. Deuxièmement, les opérations booléennes retournant une géométrie décrites ci-dessous nécessitent geometric@^3 ; sur la v2, elles retournent undefined.
Intersection de polygones et opérations booléennes
Pour les tests de chevauchement, polygonIntersection(a, b) retourne la zone partagée sous forme de nouveau polygone, tandis que polygonIntersectsPolygon(a, b) retourne un booléen. Le prédicat est la vérification économique ; l’opération retournant une géométrie vous fournit une forme réelle à afficher.
import { polygonIntersection, polygonIntersectsPolygon } from "geometric";
const a = [[0, 0], [4, 0], [4, 4], [0, 4]];
const b = [[2, 2], [6, 2], [6, 6], [2, 6]];
polygonIntersectsPolygon(a, b); // true — prédicat booléen (v2+)
polygonIntersection(a, b); // région de chevauchement sous forme de nouveau polygone (v3+)
L’ensemble complet des opérations booléennes comprend polygonIntersection, polygonUnion, polygonDifference et polygonXor, chacune retournant un tableau de points. Ces quatre opérations sont des ajouts de la v3. Pour tester la contenance plutôt que le chevauchement, polygonInPolygon(polygonA, polygonB) retourne un booléen indiquant si le premier polygone se trouve entièrement à l’intérieur du second, en traitant les points sur la frontière comme étant contenus.
Comment obtenir la boîte englobante d’un polygone ?
polygonBounds(polygon) retourne [topLeft, bottomRight] sous forme de deux points [x, y], ou null pour moins de trois sommets, ce qui suffit pour positionner une info-bulle ou un cadre de libellé autour de n’importe quelle forme en un seul appel. Elle ignore les points contenant des valeurs invalides (null, undefined, NaN, Infinity), de sorte qu’un écart isolé dans vos données ne corrompra pas la boîte.
import { polygonBounds } from "geometric";
const region = [[12, 8], [40, 20], [30, 44], [6, 30]];
const [topLeft, bottomRight] = polygonBounds(region);
// topLeft = [6, 8], bottomRight = [40, 44]
const width = bottomRight[0] - topLeft[0]; // 34
const height = bottomRight[1] - topLeft[1]; // 36
// positionnez un <rect> ou une info-bulle à topLeft avec cette largeur/hauteur
Il s’agit de la tâche de superposition courante en visualisation de données : étant donné une région arbitraire sur une carte ou un graphique, placer un cadre de libellé autour d’elle sans recalculer manuellement les valeurs min/max sur chaque sommet.
Interpolation : animer le long d’un chemin ou d’un périmètre
lineInterpolate(line) et polygonInterpolate(polygon) retournent une fonction d’interpolation que vous appelez avec t dans [0, 1], ce qui est exactement ce dont vous avez besoin pour animer un marqueur le long d’un chemin ou autour d’un périmètre. Dans la version actuelle 3.x, clamp est défini à true par défaut, limitant la sortie au segment ; le spécifier explicitement rend l’intention évidente.
import { lineInterpolate } from "geometric";
const path = [[0, 0], [100, 50]];
const at = lineInterpolate(path, true); // clamp = true
at(0); // [0, 0]
at(0.5); // [50, 25]
at(1); // [100, 50]
Pilotez t depuis requestAnimationFrame ou une transition D3, et vous obtenez un marqueur glissant le long de la ligne. polygonInterpolate fait de même autour d’un périmètre fermé, ce qui est utile pour tracer un contour ou déplacer un point le long du bord d’une forme.
Comment tester si un point se trouve à l’intérieur d’un polygone ?
Pour tester si un clic se trouve à l’intérieur d’une région, pointInPolygon(point, polygon) retourne un booléen en utilisant le lancer de rayon, sans calcul géométrique externe. Il s’agit du test de détection de clic classique sur Canvas, qui réduit une dizaine de lignes de logique de croisement d’arêtes écrite manuellement à un seul appel testé.
import { pointInPolygon, pointOnPolygon } from "geometric";
const region = [[0, 0], [100, 0], [100, 100], [0, 100]];
pointInPolygon([50, 50], region); // true
pointInPolygon([150, 50], region); // false
Les tests d’intériorité présentent une faiblesse prévisible : les clics qui tombent exactement sur une arête. Les rejeux de session lors de sélections par glisser-déposer et de sélecteurs de régions sur carte font fréquemment apparaître ce mode de défaillance : un bug du type « pourquoi ma sélection ne s’est-elle pas enregistrée ? » que les tests unitaires manquent, mais qui est évident lorsqu’on observe l’interaction. La solution appropriée est pointOnPolygon(point, polygon, epsilon), qui teste la frontière avec une tolérance epsilon optionnelle telle que 1e-6 pour l’ambiguïté de position sur la ligne, que le test d’intériorité brut ignore.
| Fonctionnalité | Fonction | Retourne | Version minimale |
|---|---|---|---|
| Test point dans une région | pointInPolygon | booléen (lancer de rayon) | v2 |
| Test de frontière | pointOnPolygon | booléen (epsilon) | v2 |
| Boîte englobante | polygonBounds | [topLeft, bottomRight] ou null | v2 |
| Forme de chevauchement | polygonIntersection | polygone | v3 |
| Prédicat de chevauchement | polygonIntersectsPolygon | booléen | v2 |
| Interpolation de chemin | lineInterpolate | fonction (t) => [x, y] | v2 |
Faites appel à Geometric.js dès qu’un graphique, une carte ou une interface Canvas nécessite plus d’une opération géométrique : le modèle tableau en entrée, tableau en sortie signifie que chaque résultat alimente l’appel suivant ou le moteur de rendu directement. Installez geometric, importez les deux ou trois fonctions dont votre fonctionnalité a besoin, et supprimez la trigonométrie copiée depuis Stack Overflow. La référence de l’API répertorie l’ensemble complet des fonctions lorsqu’une quatrième opération se présente.
FAQ
Quelle est la différence entre polygonIntersection et polygonIntersectsPolygon dans Geometric.js ?
polygonIntersectsPolygon(a, b) retourne un booléen indiquant si deux polygones se chevauchent, tandis que polygonIntersection(a, b) retourne la région partagée elle-même sous forme de nouveau tableau de polygone que vous pouvez afficher. Utilisez le prédicat pour une vérification rapide oui/non et l'opération retournant une géométrie lorsque vous avez besoin de la forme de chevauchement réelle. Le prédicat est disponible depuis la v2, mais polygonIntersection nécessite geometric v3 ou ultérieur.
Dois-je installer @types/geometric pour utiliser Geometric.js avec TypeScript ?
Non. À partir de la version 3.x, geometric intègre ses propres déclarations TypeScript générées à partir du code source et publiées avec le package, de sorte qu'installer geometric seul vous offre l'autocomplétion dans l'éditeur et la vérification des types. Le package DefinitelyTyped séparé @types/geometric est figé à la version 2.5.3 depuis novembre 2023 et est redondant avec la v3 ; l'installer peut masquer les types intégrés et précis par des types obsolètes.
Que retourne Geometric.js lorsqu'un point tombe exactement sur l'arête d'un polygone ?
pointInPolygon utilise le lancer de rayon pour tester l'intérieur, et les points qui tombent exactement sur une arête sont traités comme ambigus et peuvent retourner false, ce qui se manifeste par des clics qui ne s'enregistrent pas dans les interfaces de sélection par glisser-déposer ou de sélection de régions sur carte. Utilisez pointOnPolygon(point, polygon, epsilon) pour les cas de frontière ; la tolérance epsilon optionnelle, telle que 1e-6, contrôle la proximité à la ligne qui est considérée comme étant dessus.
La sortie de Geometric.js peut-elle être dessinée directement en SVG ou sur Canvas sans conversion ?
Oui. Étant donné que chaque primitive est un simple tableau JavaScript plutôt qu'une instance de classe, les tableaux retournés par des fonctions telles que polygonRegular ou polygonIntersection s'intègrent directement dans un attribut SVG points ou une boucle Canvas ctx.lineTo sans aucun code adaptateur. Le même tableau que vous calculez est la valeur que vous sérialisez en JSON, transmettez à D3 ou affichez, ce qui constitue le principe de conception fondamental de la bibliothèque.
Gain Debugging Superpowers
Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers.
Star on GitHub12k