Mini-carte
Le mode full ancre déjà un aperçu de l'ensemble du graphique dans un coin du canevas, et une ligne - plugins: [minimap()], comme ci-dessous - y place votre propre configuration, dans n'importe quel mode. Cliquez n'importe où pour y amener la vue ; faites glisser le rectangle vers lequel effectuer un panoramique. Le graphique ci-dessous est plus large que sa fenêtre d'affichage, il y a donc un endroit où aller. La petite flèche dans le coin intérieur de la mini-carte la replie sur ce seul bouton lorsque le canevas compte plus que l'aperçu.
Même s'il s'agit d'un plugin, pas d'un chrome intégré — le mode full l'installe simplement pour vous et met de côté la copie transmise ici. Il s'installe via le PluginContext qui lui est remis et n'utilise rien qu'un plugin de votre choix ne puisse faire — il lit l'étendue du graphique avec renderer.getContentBounds(), détermine la région visible en inversant les coins du canevas via renderer.screenToGraphCoordinates() et déplace la vue avec renderer.setViewport(). Voir Plugins pour toute la surface.
Cela reste également bon marché sur un graphique qui en a réellement besoin. L'image se trouve dans un bitmap hors écran mis en cache qui n'est re-rastérisé que lorsque le graphique change (ou tous les 10 ticks de simulation pendant qu'une mise en page se stabilise) ; le panoramique et le zoom redessinent une image et un rectangle, quel que soit le nombre de nœuds. Au-delà de 1 500 nœuds, il arrête de dessiner chaque nœud et peint la densité à la place, ce qui se lit mieux que des dizaines de milliers de points qui se chevauchent et ne résout aucun style par nœud.
Effectuez un zoom avant avec les commandes de la fenêtre, puis faites glisser le rectangle dans la mini-carte : l'image du contenu ne se redessine jamais, seul le rectangle se déplace.
// import { minimap } from 'pivotick'
const options = {
UI: {
// `full` mode brings a minimap of its own; `light` and `viewer` need asking
// (`UI.minimap: true`, or the plugin below). `static` never has one.
mode: 'full',
// The other thing full mode brings. Off here: this card is about the minimap.
table: false
},
// A plugin installs itself through the PluginContext it is handed — the core never
// needs to know it exists. `graph.use(minimap())` works just as well, at any time.
// Passed here it replaces the one full mode would have mounted, configuration and all.
plugins: [
minimap({
position: 'bottom-right', // the corner the built-in chrome leaves free
width: 220
// height: omitted → follows the canvas's aspect ratio
})
],
render: {
nodeTypeAccessor: (node) => node.getData()?.kind,
nodeStyleMap: {
hub: { color: '#0072B2', size: 13 },
leaf: { color: '#E69F00', size: 7 }
}
},
simulation: {
d3LinkDistance: 60
}
}// A graph deliberately bigger than the viewport, so the minimap has something to
// navigate: six clusters of satellites around a spine.
const nodes = []
const edges = []
const hubs = ['alpha', 'beta', 'gamma', 'delta', 'epsilon', 'zeta']
hubs.forEach((hub, hubIndex) => {
const angle = (hubIndex / hubs.length) * Math.PI * 2
nodes.push({
id: hub,
data: { name: hub, kind: 'hub' },
x: Math.cos(angle) * 420,
y: Math.sin(angle) * 420
})
if (hubIndex > 0) edges.push({ from: hubs[hubIndex - 1], to: hub })
for (let leafIndex = 0; leafIndex < 9; leafIndex++) {
const id = `${hub}-${leafIndex}`
const spread = (leafIndex / 9) * Math.PI * 2
nodes.push({
id,
data: { name: id, kind: 'leaf' },
x: Math.cos(angle) * 420 + Math.cos(spread) * 130,
y: Math.sin(angle) * 420 + Math.sin(spread) * 130
})
edges.push({ from: hub, to: id })
}
})
const data = { nodes, edges }