Fourmis.js
À propos
Développée dans le cadre du projet Déborder Bolloré, fourmis.js
est une bibliothèque JavaScript permettant l’insertion de fourmis sur une page web.
Les fourmis peuvent prendre différents comportements définis dans src/behaviors/
, l’implémentation de l’interaction utilisateur est laissée à la discrétion du·de la développeur·euse.
Pour plus d’informations, consulter le dépôt sur GitLab.
Fonctionnement
Les fourmis sont ajoutées au DOM en tant que symboles SVG.
Les coordonnées sont exprimées dans le référentiel absolu de leur conteneur, c’est-à-dire qu’une fourmi positionnée en (0; 0)
sera placée dans le coin haut-gauche de son conteneur.
À l’insertion d’une nouvelle fourmi aux coordonnées (x; y)
, la bibliothèque vérifie la place disponible au sein d’un éventuel cluster de fourmis déjà présentes aux alentours, et modifie la position d’insertion le cas échéant. Ensuite, une fonction de comportement définie par la propriété behavior
défini l’angle de la fourmi en fonction de ses coordonnées d’insertion définitives.
Une fois instanciée, la bibliothèque propose plusieurs méthodes permettant l’ajout et la suppression des fourmis.
API
L’intégralité du code source est documenté au format JSDoc.
Voir src/index.js
pour commencer.
Exemples
#1 : Ajout simple de fourmis
import { Fourmis } from '@deborderbollore/fourmis.js'
const container = document.querySelector('#example-1 .viewport')
const fourmis = new Fourmis({ container })
container.addEventListener('click', e => {
const x = e.clientX + document.documentElement.scrollLeft - container.offsetLeft
const y = e.clientY + document.documentElement.scrollTop - container.offsetTop
fourmis.push([x, y])
})
#2 : Orientation vers un élément HTML
import { Fourmis, seek } from '@deborderbollore/fourmis.js'
const container = document.querySelector('#example-2 .viewport')
const fourmis = new Fourmis({
container,
behavior: seek(container.querySelector('.target'), {
attractionRadius: container.clientWidth * 0.5
})
})
container.addEventListener('click', e => {
const x = e.clientX + document.documentElement.scrollLeft - container.offsetLeft
const y = e.clientY + document.documentElement.scrollTop - container.offsetTop
fourmis.push([x, y])
})
#3 : Suivi d’un contour SVG
import { Fourmis, sneakAroundPaths } from '@deborderbollore/fourmis.js'
const container = document.querySelector('#example-3 .viewport')
const fourmis = new Fourmis({
container,
behavior: sneakAroundPaths(container.querySelectorAll('svg path'))
})
container.addEventListener('mousemove', e => {
if (e.buttons !== 1) return
window.requestAnimationFrame(() => {
const x = e.clientX + document.documentElement.scrollLeft - container.offsetLeft
const y = e.clientY + document.documentElement.scrollTop - container.offsetTop
fourmis.push([x, y])
})
})
#4 : Composition de plusieurs comportements
import { Fourmis, compose, sneakAroundPaths, seek, wander } from '../src'
const container = document.querySelector('#example-4 .viewport')
const fourmis = new Fourmis({
container,
// Compose multiple behaviors
behavior: compose([
// Wander on the viewport
wander(),
// Seek center of SVG
seek(container.querySelector('svg'), {
maxDistance: container.clientHeight * 0.75
}),
// Sneak around SVG path elements, but with a weight twice as contrasted as the other behaviors
compose.weight(
sneakAroundPaths(container.querySelectorAll('svg path'), { maxDistance: 50 }),
w => w + w * w
)
])
})
container.addEventListener('mousemove', e => {
if (e.buttons !== 1) return
window.requestAnimationFrame(() => {
const x = e.clientX + document.documentElement.scrollLeft - container.offsetLeft
const y = e.clientY + document.documentElement.scrollTop - container.offsetTop
fourmis.push([x, y])
})
})
#5 : Comportement personnalisé
import { Fourmis } from '../src'
const container = document.querySelector('#example-5 .viewport')
const fourmis = new Fourmis({
container,
behavior: followPrevious
})
const distSq = (a, b) => (b[0] - a[0]) * (b[0] - a[0]) + (b[1] - a[1]) * (b[1] - a[1])
const getPoint = e => ([
e.clientX + document.documentElement.scrollLeft - container.offsetLeft,
e.clientY + document.documentElement.scrollTop - container.offsetTop
])
let lastPoint
container.addEventListener('mousedown', e => { lastPoint = getPoint(e) })
container.addEventListener('mousemove', e => {
if (e.buttons !== 1) return
window.requestAnimationFrame(() => {
const point = getPoint(e)
if (distSq(point, lastPoint) > 20 ** 2) {
const agent = fourmis.push(point)
if (agent) lastPoint = agent.point
}
})
})
function followPrevious (instance) {
const angleBetween = ([x1, y1], [x2, y2]) => Math.atan2(y2 - y1, x2 - x1)
return point => ({
point,
theta: angleBetween(lastPoint, point)
})
}
Crédits
Fourmi dessinée par Alaric Garnier.